ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I have a series of images of an object taken on a tripod. People kept moving in and out of the pictures. I would like to take this time series set of pictures and remove the differences.
The command "convert -average" almost does this but leaves "ghosts" of the objects that move in an out of the photo.
How can I preserve those parts of the photo that are constant, removing the changed parts
The SSIM script seems to be able to create an image showing the dissimilarities in two images. Maybe you can take it from there with some boolean functions.
Fred's scripts often need a bit of work. I gave it a go and the script crashes for a variety of reasons. I may look at it some more if I run out of option. anyway thanks for the suggestion.
This struck me as a interesting problem, so I wrote a python script to do the following:
Take a set of images
For each image, get color information for pixel 0,0.
Find the most common one.
Repeat for every other pixel.
Write most common pixels to array and write out as a image.
That's all it does, so it's pretty dumb for "interpreting" a image. I've never written a image manipulation program before so consider this experimental
It works great for controlled images (like screenshots) but left ghosts of images with my camera.. Probably because even though things seem mostly similar.. they do change a little.
The more pictures of what you want will likely get what you want.. probably. I'd also suggest processing it as minimally as possible into something with lossless compression.
You will need PIL and numpy installed and works with tiff, png and will probably work with most image formats (whatever PIL recognizes)
EDIT: See the below post for a better implementation of this code.
#!/usr/bin/env python3
# https://www.linuxquestions.org/questions/programming-9/imagemagick-remove-differences-4175611638/#post5746930
# Author: Sefyir
import sys
import argparse
from collections import Counter
import numpy as np
from PIL import Image
def load_image(infilename):
with Image.open(infilename) as img:
img.convert('L')
return np.array(img)
def save_image(image_array, save_location):
image = Image.fromarray(image_array)
image.save(save_location)
print('Saved to {}'.format(save_location))
def file_bit_array_func(array):
'''Get location and array for each pixel'''
return ((row_index, column_index, pixel_array)
for row_index, row in enumerate(array)
for column_index, pixel_array in enumerate(row)
)
def create_bit_list(image_arrays):
'''
Find most common pixel in image array
All images must have identical dimensions
'''
for image_array in zip(*image_arrays):
row_index = image_array[0][0]
column_index = image_array[0][1]
bit_array_most_common = Counter((tuple(image[2]) for image in image_array))
# Frequency of most common color values.
# If most common is 1, all were different.
# Find median of each color value
if bit_array_most_common.most_common(1)[0][1] == 1:
image_info_list = (tuple(pixel_info[2]) for pixel_info in image_array)
median_array = tuple(np.median(pixel_zipped_array)
for pixel_zipped_array in zip(*image_info_list))
bit_array_most_common = np.array([int(num) for num in median_array], dtype='uint8')
else:
bit_array_most_common = np.array(bit_array_most_common.most_common(1)[0][0], dtype='uint8')
yield (row_index, column_index, bit_array_most_common)
parser = argparse.ArgumentParser('Merge Common Pictures')
parser.add_argument('-o', '--output')
args, other_args = parser.parse_known_args()
image_arrays = (file_bit_array_func(load_image(_file))
for _file in other_args)
# Grab image array to serve as template for each row / column to change.
with Image.open(other_args[0]) as image_file:
image_file.convert('L')
source_image_array = np.array(image_file)
# Write most common values to source image array
for row_index, column_index, bit_array in create_bit_list(image_arrays):
source_image_array[row_index][column_index] = bit_array
save_image(source_image_array, args.output)
I updated it to now be able to handle more diversity in images.
It will check each pixel and find the most common, if there is no most common (each one occurs once) then it finds the median of the colors (not the average!)
It worked well in the experiment I ran The camera tilted a bit in one of them which you can notice. Examine the links to see the source 4 images and the resultant image.
Note it is not fast, I ran with 5 RAW 4k images with a neutral profile converted to 8-bit uncompressed tiffs and it took 14min, 50s to complete (about 3min per image).
Smaller / fewer images will of course go faster.
This program could be extremely useful.
Imagemagick is great but each command is pretty much a black box.
A Python program is something to which I can do my own mods.
My problem is the program crashes in "save format = EXTENSION[ext]"
My images are jpeg images, fairly large 6M. Can you suggest what is causing this.
Sefyir, you say you have updated to handle a greater diversity in images but where is the update?
The code appears well written but there is not a single line of comments.
This makes it extra work for me not being au fait with Python's PIL.
I can learn but a few clues in the code is very helpful. ( What does zip(*image) do?)
What may be needed to help the program is a means of aligning the pixels across two or more images. I think Imagemagick has something but it would be best to have it in this code.
Anyway its great to see someone this enthusiastic. This could help me a great deal when it works/
My problem is the program crashes in "save format = EXTENSION[ext]"
My images are jpeg images, fairly large 6M. Can you suggest what is causing this.
A traceback or actual error would be good. Trial converting to a uncompressed non lossy format (like tif or png) and try again?
Quote:
The code appears well written but there is not a single line of comments.
This makes it extra work for me not being au fait with Python's PIL.
I was writing in a cycle of coding and testing. Unfortunately, not the best style for good comments. There is a style where the variables and method names should describe what the code is doing as well as comments, but the above code is a example of where I did very poorly at that.
I went over it to make it read better... However a idea occurred to me that rendered much of my code redundant. Before I get to that, I'll address this:
Quote:
What does zip(*image) do?
This made it possible to take a list of images converted to arrays, and iterate over the first pixel in each image simultaneously. Assume Image A was a single pixel of white, it would be (255, 255, 255). If image 2 was black, (0, 0, 0) and Image 3 black, (0, 0, 0)
Then you could do this:
As you can see, the first of each was in the first tuple, the second of each in the second tuple.. so forth.
Ok, this new code is now a class (I re-factored) and now leverages the arrays to a greater amount of power.
Specifically, I use numpy to stack the 3 dimensional arrays on top of each other and then..
Calculate the median of values in the 4th dimension (or axis?). Or.. something like that . Anyways, side bonus of instead of a 15-minute wait, it's now about 5s as well as much simpler to understand!
Code
EDIT:
The code is fully classes, you just need to inherit ImageArray and define _process_image and you can have it do whatever you want with the stacked images. Feel free to look at ImageMedian and ImageMean as examples
Any modification would benefit best from vectorized calculations on the array, but it's not required since you can use zip and loops to simulate that (albeit much slower!)
Code:
#!/usr/bin/env python3
import sys
import argparse
import numpy as np
from PIL import Image
class ImageArray():
'''
Load each image into a array, stack on top on other image arrays
and run _process_image
'''
def __init__(self, images):
self.images = (self._load_image(image)
for image in images)
self.stacked_image_arrays = np.stack(self.images)
self.flattened_image_array = self._process_image(self.stacked_image_arrays)
def _load_image(self, _file):
with Image.open(_file) as img:
return np.array(img)
def save_image(self, save_location):
image = Image.fromarray(self.flattened_image_array.astype('uint8'))
image.save(save_location)
print(f'Saved to {save_location}')
def _process_image(self):
pass
class ImageMedian(ImageArray):
'''Collapse image array into median of each pixel'''
def __init__(self, images):
super().__init__(images)
def _process_image(self, stacked_image_arrays):
if len(stacked_image_arrays) < 3:
raise ValueError('Requires 3 or more images')
flattened_median_image_array = np.median(stacked_image_arrays, axis=0)
return flattened_median_image_array
class ImageMean(ImageArray):
'''Collapse image array into mean of each pixel'''
def __init__(self, images):
super().__init__(images)
def _process_image(self, stacked_image_arrays):
flattened_mean_image_array = np.mean(stacked_image_arrays, axis=0)
return flattened_mean_image_array
if __name__ == '__main__':
parser = argparse.ArgumentParser('Merge Common Pictures')
parser.add_argument('-o', '--output',
default='output.jpg')
args, source_images = parser.parse_known_args()
DemoImages = ImageMedian(source_images)
#DemoImages = ImageMean(source_images)
DemoImages.save_image(args.output)
Putting a camera on tripod and taking four images of a bowl of fruit with a banana that moves in front of the bowl. Original images had a much large pixel resolution but here are attached, reduced eight times to be a little less of a space hog. Running those images through the last program you supplied renders the jpeg image ofile.jpg The result almost removes the banana entirely.
That's a good result.
For your interest I am a keen scuba diver. I am making a composite photograph taking sections along the length of a shipwreck and stitching the parts together to make a very large high res picture. The trouble is (was) that fish kept getting in the way and spoiling the stitch. With this program I can do a time series on each stitch and remove the fish, then do the stitch.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.