Hi I am trying to compare a set of images where I want to produce a final image with maximum pixels from each individual image. Say I have 3 images (converted to 10x10 matrix) in which I know the pixel values of each block> Now I want to compare these values block by block and produce a final separate image with maximum block values from each image.
To do so I have changed the image dimensions(250x250) such that each block is a square of 25x25
I even tried comparing two images and taking the maximum pixels from both the images and displaying them
image = cv2.resize(im,(250,250))
hs,ws,c= image.shape
print(hs, ws,c)
hs = round(h/10)
ws = round(w/10)
resized = cv2.resize(image, (ws,hs), interpolation = cv2.INTER_AREA)
cv2.imshow("Resized image", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()
print(list(resized))
#comparing two images
data = np.maximum.reduce([resized,resized1])
from matplotlib import pyplot as plt
plt.imshow(data, interpolation='nearest')
plt.show()
So these are two images and the tiled image is the result of the block #comparing two images. Now using these two images I want to produce a final image similar to the original photos not the tiled version but the final photo should have pixels from both original photos(maximum from each). I hope it clears the question
For better visualization purposes, I skip the whole resizing part you got earlier, and stick to resized (250 x 250) images.
My approach is the following: Store all your resized images in some NumPy array with dimensions (width x height x numberOfChannels x numberOfImages), and then use NumPy's max along axis=3, such that you get a final image (width x height x numberOfChannels) with maximum BGR values (or grayscale, if desired) over all images.
Here's some exemplary code:
import cv2
import numpy as np
# Set up empty images array
width, height, nChannels, nImages = (250, 250, 3, 3)
images = np.zeros((width, height, nChannels, nImages), np.uint8)
# Read and resize exemplary input images
images[:, :, :, 0] = cv2.resize(cv2.imread('WeQow.png'), (width, height))
images[:, :, :, 1] = cv2.resize(cv2.imread('gIHOd.png'), (width, height))
images[:, :, :, 2] = cv2.resize(cv2.imread('lAdfO.jpg'), (width, height))
# Generate maximum image along last axis, i.e. the images.
# For each BGR value you get the maximum over all images.
image = images.max(axis=3)
# Show images
cv2.imshow('image0', images[:, :, :, 0])
cv2.imshow('image1', images[:, :, :, 1])
cv2.imshow('image2', images[:, :, :, 2])
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
These are the three input images:
The final output image then looks like this:
Hope that helps!
You can try using block_reduce function with block size (no_of_images, channels, block_height, block_width).
skimage.measure.block_reduce(np.asarray([image1, image2, image3,...]), (no_of_images, channels, 1, 1), np.max)
If your input images are in RGB scale and you want per-channel max value (output also RGB image) among images just replace channels value with 1 or if you want max value across channels among the images then use 3 as channels value that will generate a gray scale image.
Related
I have a multiple pictures with different dimensions. I have been trying to concat them horizontally using openCV.
The process is kind of following:
Iterate over all the images to find the max width and total height.
Create a black mask that is with the size of max width and total height got from all the images.
Stack all the images horizontally on that black mask.
I am not sure how to do this thing. Kindly help me!
Images are just 3D matrices, so you can do this very easily by creating a matrix of zeros (= black) of the desired size, then filling in your images.
I've created fake images here but you can use cv2 to read in your real images.
import numpy as np
import matplotlib.pyplot as plt
# create three images of different shapes and different shades of grey
img1 = np.ones((100, 200, 3), dtype=int)*50
img2 = np.ones((200, 400, 3), dtype=int)*100
img3 = np.ones((100, 300, 3), dtype=int)*150
imgs = [img1, img2, img3]
# get max width and total height
max_width = 0
total_height = 0
for img in imgs:
total_height += img.shape[0]
max_width = max(max_width, img.shape[1])
# make black canvas of appropriate shape
canvas = np.zeros((total_height, max_width, 3), dtype=int)
# stack images on canvas
start_height = 0
for img in imgs:
print(img.shape)
canvas[start_height:start_height+img.shape[0], 0:img.shape[1], :] = img
start_height+= img.shape[0]
# show results
plt.imshow(canvas)
This produces the following result:
I need to stack two images with the same width to create a new image.
I currently have two images which are slices of the same image:
img is the name of the original image with shape (480, 640, 3)
timestamp = img[:40, :200, :]
variables = img[370:, :200, :]
I either want to stack these images somehow or slice the original image in such a way that I take the first 40 pixels and the last 90 pixels (as above)
Thanks in advance!
You can use np.vstack:
new_img = np.vstack([img[:40, :200, :], img[370:, :200, :]])
I am trying to add columns and rows on all sides.
padded_array = np.zeros([img.shape[0] + (size//2) + (size//2), img.shape[1] + (size//2) + (size//2)])
padded_array[size//2 : padded_array.shape[0]-(size//2), size//2 : padded_array.shape[1]-(size//2)] = gray
Here, img is the original image and gray is the gray-scaled image and shape of both of them is same.
Now, I am trying to create a padded_array by adding (size//2) rows on top and below and
(size//2) columns left and right.
size is always odd.
When I try to pad, I don't understand why the gray image is not broadcasted into the padded array.
Instead, what it is doing is broadcasting value 255 on all pixels in that range of gray image and padded rows and columns are left blank.
I am adding the screenshots of both the images, please have a look.
Gray Scale Image is :
Padded Image after broadcasting gray is :
You can divide image width / image height and multiply with a constant.
import matplotlib.pyplot as plt
def pad(image, h=2):
w = (image.shape[0]/image.shape[1]) * h
plt.figure(figsize=(w, h))
plt.imshow(im)
plt.axis('off')
plt.show()
im = plt.imread('blur.png')
pad(im)
Output:
The mistake here was while defining the padded_array I didn't define the data type of array to be int, it was float by default and that was the reason for white image, as soon as I defined the data in padded_array are int, everything turned out fine.
Code works fine while reading a gray scale image to perform brightness. But same code doesn't work with color image.
How to perform brightness operation from a color image?
While reading the image using cv2.imread at the argument 0 works fine but I tried with 1 it doesn't work as 0 is for gray scale image and 1 for color image.
import numpy as np
import cv2
img = cv2.imread('image1.jpg',1)
height = img.shape[0]
width = img.shape[1]
brightness = 100
for i in np.arange(height):
for j in np.arange(width):
a = img.item(i,j)
b = a + brightness
if b > 255:
b = 255
img.itemset((i,j), b)
cv2.imwrite('brightness.jpg', img)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
I expect a color image to be read and perform brightness operation but it is showing ValueError: incorrect number of indices for array
The problem is a colored image has multiple channels for the different color (example, RGB or RGBA) so when you do img.item(i,j) you are missing the third dimension (the three color channels). You can add another for loop that loops over each of the color channels but you can also just use numpy's minimum function to make it more efficient (i.e. add 255 to the values of your image and if it's greater than 255 it will use 255).
import numpy as np
import cv2
img = cv2.imread('image1.jpg',1)
brightness = 100
np.minimum(img + brightness, 255)
cv2.imwrite('brightness.jpg', img)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
One solution is to use OpenCV normalize to stretch the image to full dynamic range (0 to 255).
Here are two output results depending upon the min and max stretch limits. Note that normalize works on float data and the min and max values are nominally stretched to full range of 0 to 1. But we ned to clip the results to this range and then scale them to the range 0 to 255 before saving as uint8 for output, if the min and max values are outside the range of 0 to 1.
The first result is stretched to min and max of 0 to 1.
The second result is stretched to min and max of 0 to 1.2 in order to make it even brighter.
Image:
#!/bin/python3.7
import cv2
import numpy as np
# read image
img = cv2.imread("zelda1_bm20_cm20.jpg", cv2.IMREAD_COLOR)
# normalize float versions
norm_img1 = cv2.normalize(img, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)
norm_img2 = cv2.normalize(img, None, alpha=0, beta=1.2, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)
# scale to uint8
norm_img1 = (255*norm_img1).astype(np.uint8)
norm_img2 = np.clip(norm_img2, 0, 1)
norm_img2 = (255*norm_img2).astype(np.uint8)
# write normalized output images
cv2.imwrite("zelda1_bm20_cm20_normalize1.jpg",norm_img1)
cv2.imwrite("zelda1_bm20_cm20_normalize2.jpg",norm_img2)
# display input and both output images
cv2.imshow('original',img)
cv2.imshow('normalized1',norm_img1)
cv2.imshow('normalized2',norm_img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Min and Max (0 to 1):
Min and Max (0 to 1.2):
I have an array of pixels
np.shape(pred2)
Out[35]: (3000, 3, 32, 32)
It has 3000 images, 3 values rgb and is 32*32 in size for each image. I want to create an image from this.
Here is what I have so far:
img = Image.new( 'RGB', (32,32), "black") # create a new black image
pixels = img.putdata(pred2[1,:])
Can anyone give me a hand here as to what I am doing wrong?
Images are shape (h, w, 3), not (3, h, w). You need to permute your axes accordingly. Depending on whether you care about width vs height, it appears you can just do:
im = pred2[1].T
scipy.misc.imsave('the_image_file.png', im)