Reputation: 2345
If I have a list of images represented by 3D ndarray such as [[x,y,color],...]
, what operations can I use to output an image with values that are median of all values? I am using a for loop and find it too slow.
Upvotes: 6
Views: 7045
Reputation: 1394
You said your images in color, formatted as a list of 3d ndarrays
. Let's say there are n
images:
imgs = [img_1, ..., img_n]
Where imgs is a list
and each img_i
is a an ndarray
with shape (nrows, ncols, 3)
.
Convert the list to a 4d ndarray, then take the median over the dimension that corresponds to images:
import numpy as np
# Convert images to 4d ndarray, size(n, nrows, ncols, 3)
imgs = np.asarray(imgs)
# Take the median over the first dim
med = np.median(imgs, axis=0)
This gives the pixel-wise median. The value of each color channel of each pixel is the median of the corresponding pixel/channel in all images.
The documentation for asarray()
says "no copy is performed if the input is already an ndarray". This suggests that the operation would be faster if you stored the original list of images as a 4d ndarray
instead of a list. In that case, it wouldn't be necessary to copy the information in memory (or to run asarray()
)
Upvotes: 5
Reputation: 12142
This is my vectorized implementation using NumPy:
For my test I used these five images:
The relevant parts:
import numpy as np
import scipy.ndimage
# Load five images:
ims = [scipy.ndimage.imread(str(i + 1) + '.png', flatten=True) for i in range(5)]
# Stack the reshaped images (rows) vertically:
ims = np.vstack([im.reshape(1,im.shape[0] * im.shape[1]) for im in ims])
# Compute the median column by column and reshape to the original shape:
median = np.median(ims, axis=0).reshape(100, 100)
The complete script:
import numpy as np
import scipy.ndimage
import matplotlib.pyplot as plt
ims = [scipy.ndimage.imread(str(i + 1) + '.png', flatten=True) for i in range(5)]
print ims[0].shape # (100, 100)
ims = np.vstack([im.reshape(1,im.shape[0] * im.shape[1]) for im in ims])
print ims.shape # (5, 10000)
median = np.median(ims, axis=0).reshape(100, 100)
fig = plt.figure(figsize=(100./109., 100./109.), dpi=109, frameon=False)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
plt.imshow(median, cmap='Greys_r')
plt.show()
The median (numpy.median
) result of the five images looks like this:
Fun part: The mean (numpy.mean
) result looks like this:
Okay, science meets art. :-)
Upvotes: 7