Trying to match two images to find out the scores between them.But it shows some dimension error.Unable to fix the issue.My code is given below:
from skimage.measure import compare_ssim
#import argparse
#import imutils
import cv2
img1="1.png"
img2="2.png"
# load the two input images
imageA = cv2.imread(img1)
imageB = cv2.imread(img2)
# convert the images to grayscale
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)
# compute the Structural Similarity Index (SSIM) between the two
# images, ensuring that the difference image is returned
(score, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")
print("SSIM: {}".format(score))
This give n an error:
raise ValueError('Input images must have the same dimensions.')
ValueError: Input images must have the same dimensions.
How to fix this issue?
Amending Saurav Panda's answer:
You can reshape one of the images to the size of other image like this:
imageB=cv2.resize(imageB,imageA.shape)
note that
(H, W) = imageA.shape
# to resize and set the new width and height
imageB = cv2.resize(imageB, (W, H))
the cv2.resize function inputs expects (W,H). This is the reverse order of the output of cv2.shape (H,W), so you need to catch that, or you'll get the same error when comparing non-square images.
You can do this in many ways:
Like in the first method, you can assign a fixed dimension which would be less than the actual dimensions of the image and resize both images to this same size. Like, resize all images to (150,150), etc.
In second method you can reshape one of the images to the size of other images.
Try this code:
imageB=cv2.resize(imageB,imageA.shape)
This will work for you, but in case the difference in dimensions of two image is very large, sometimes you may lose some data. You can compare for both x and y dimensions and find the smallest one.Then resize both images to this smallest dimension of x and y.
The error
'Input images must have the same dimensions.'
Tells you that the function you called expects input images of the same dimensions and that you did not do this.
You obviously fix that by providing input images that have the same dimensions or by not calling that function if the images have different dimensions and if you cannot change that for whatever reason.
Compare imageA.shape and imageB.shape after loading the images from file.
For simple debugging:
print imageA.shape
print imageB.shape
You can use tensorflow. See this link and you can modify your data accordingly
Related
I have the following code portion:
dataset = trainDataset()
train_loader = DataLoader(dataset,batch_size=1,shuffle=True)
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
images = []
image_labels = []
for i, data in enumerate(train_loader,0):
inputs, labels = data
inputs, labels = inputs.to(device), labels.to(device)
inputs, labels = inputs.float(), labels.float()
images.append(inputs)
image_labels.append(labels)
image = images[7]
image = image.numpy()
image = image.reshape(416,416,3)
img = Image.fromarray(image,'RGB')
img.show()
The issue is that the image doesn't display properly. For instance, the dataset I have contains images of cats and dogs. But, the image displayed looks as shown below. Why is that?
EDIT 1
So, after #flawr's nice explanation, I have the following:
image = images[7]
image = image[0,...].permute([1,2,0])
image = image.numpy()
img = Image.fromarray(image,'RGB')
img.show()
And, the image looks as shown below. Not sure if it is a Numpy thing or the way the image is represented and displayed? I would like to also kindly note that I get a different display of the image at every run, but it is pretty much something close to the image displayed below.
EDIT 2
I think the issue now is with how to represent the image. By referring to this solution, I now get the following:
image = images[7]
image = image[0,...].permute([1,2,0])
image = image.numpy()
image = (image * 255).astype(np.uint8)
img = Image.fromarray(image,'RGB')
img.show()
Which produces the following image as expected :-)
In pytorch you usually represent pictures with tensors of shape
(channels, height, width)
You then seem to reshape it to what you expect would be
(height, width, channels)
Note that these tensors or arrays are actually stored as 1d "array", and the multiple dimensions just come from defining strides (check out How to understand numpy strides for layman?).
In your particular case this means that consecutive values (that were basically values of the same color channela and the same row) are now interpreted as different colour channels.
So let's say you have a 2x2 image with 3 color channels. Let's say it is a chessboard pattern. In pytorch that would looks something like the following array of shape (3, 2, 2):
[[[1,0],[0,1]],[[1,0],[0,1]],[[1,0],[0,1]]]
The underlaying internal array is just
[ 1,0 , 0,1 , 1,0 , 0,1 , 1,0 , 0,1 ]
So reshaping to (2, 2, 3) would look like so:
[[[1,0,0],[1,1,0]],[[0,1,1],[0,0,1]]]
which immediately shows how the image will be completely jumbled. Reshaping really just means setting the brackets in different places!
So what you probably want instead of reshape is permute([1, 2, 0]), (or in numpy called transpose) which will actually rearrange the data.
I was doing some face verification stuff(I'm a newbie) first I vectorize the 2 pics I want to compare
filename1 = '/1_52381.jpg'
filename2 = '/1_443339.jpg'
img1 = plt.imread(filename1)
rows,cols,colors = img1.shape
img1_size = rows*cols*colors
img1_1D_vector = img1.reshape(img1_size).reshape(-1, 1)
img2 = plt.imread(filename2)
rows,cols,colors = img2.shape
img2_size = rows*cols*colors
img2_1D_vector = img2.reshape(img2_size).reshape(-1, 1)
(img2_1D_vector.shape,img1_1D_vector.shape)
and here I get the dim of the both vector which is: ((30960, 1), (55932, 1)).
My question is how to make them both of the same length do I need to reshape the picture to have the same size first? or I can do it after vectorize it? thanks for reading
Yes, to compute a cosine similarity you need your vectors to have the same dimension, and resizing one of the pictures before reshaping it into a vector is a good solution.
To resize, you can use one of image processing framework available in python.
Note: they are different algorithm/parameters that can be use for resizing.
# with skimage (you can also use PIL or cv2)
from skimage.transform import resize
shape = img1.shape
img2_resized = resize(img1, shape)
img1_vector = img1.ravel()
img2_vector = img2_resized.ravel()
# now you can perform your cosine similarity between img1_vector and img2_vector
# which are of the same dimension
you may wan't to downscale the bigger picture instead of upscaling the smaller one as upscaling may introduce more artefacts.
You may also want to work with a fixed size accross a whole dataset.
I'm using this code with python and opencv for displaying about 100 images. But imshow function throws an error.
Here is my code:
nn=[]
for j in range (187) :
nn.append(j+63)
images =[]
for i in nn:
path = "02291G0AR\\"
n1=cv2.imread(path +"Bi000{}".format(i))
images.append(n1)
cv2.imshow(images)
And here is the error:
imshow() missing required argument 'mat' (pos 2)
You have to visualize one image at a time, while you are passing images which is a list
cv2.imshow() takes as first argument the name of the window
So you should iterate on your loaded images like:
for image in images:
cv2.imshow('Image', image)
cv2.waitKey(0) # Wait for user interaction
You may want to take a look to the python opencv documentation about displaying images here.
You can use the following snippet to montage more than one image:
from imutils import build_montages
im_shape = (129,196)
montage_shape = (7,3)
montages = build_montages(images, im_shape, montage_shape)
im_shape : A tuple containing the width and height of each image in the montage. Here we indicate that all images in the montage will be resized to 129 x 196. Resizing every image in the montage to a fixed size is a requirement so we can properly allocate memory in the resulting NumPy array. Note: Empty space in the montage will be filled with black pixels.
montage_shape : A second tuple, this one specifying the number of columns and rows in the montage. Here we indicate that our montage will have 7 columns (7 images wide) and 3 rows (3 images tall).
I need to split an RGBA image into an arbitrary number of boxes that are as equally sized as possible
I have attempted to use numpy.array_split, but am unsure of how to do so while preserving the RGBA channels
I have looked the following questions, none of them detail how to split an image into n boxes, they reference splitting the image into boxes of predetermined pixel size, or how to split the image into some shape.
While it seems that it would be some simple math to get number of boxes from box size and image size, I am unsure of how to do so.
How to Split Image Into Multiple Pieces in Python
Cutting one image into multiple images using the Python Image Library
Divide image into rectangles information in Python
While attempting to determine the number of boxes from pixel box size, I used the formula
num_boxes = (img_size[0]*img_size[1])/ (box_size_x * box_size_y)
but that did not result in the image being split up properly
To clarify, I would like to be able to input an image that is a numpy array of size (a,b,4) and a number of boxes and output the images in some form (np array preferred, but whatever works)
I appreciate any help, even if you aren't able to provide the full method, I would appreciate some direction.
I have tried
def split_image(image, n_boxes):
return numpy.array_split(image,n_boxes)
#doesn't work with colors
def split_image(image, n_boxes):
box_size = factor_int(n_boxes)
M = im.shape[0]//box_size[0]
N = im.shape[1]//box_size[1]
return [im[x:x+M,y:y+N] for x in range(0,im.shape[0],M) for y in range(0,im.shape[1],N)]
factor_int returns integer as close to a square as possible from Factor an integer to something as close to a square as possible
I am still not sure if your inputs are actually the image and the dimensions of the boxes or the image and the number of boxes. Nor am I sure if your problem is deciding where to chop the image or knowing how to chop a 4-channel image, but maybe something in here will get you started.
I started with this RGBA image - the circles are transparent, not white:
#!/usr/bin/env python3
from PIL import Image
import numpy as np
import math
# Open image and get dimensions
im = Image.open('start.png').convert('RGBA')
# Make Numpy array from image and get height and width
ni = np.array(im)
h ,w = ni.shape[:2]
print(f'Height: {h}, width: {w}')
BOXES = 4
for i in range(BOXES):
this = ni[:, i*w//BOXES:(i+1)*w//BOXES, :]
Image.fromarray(this).save(f'box-{i}.png')
You can change BOXES but leaving it at 4 gets you these 4 output images:
[] []4
import cv2
import numpy as np
from PIL import Image
from skimage import morphology
from scipy import signal
img = cv2.imread('thin.jpg',0)
img1 = cv2.imread('thin1.jpg',0)
cv2.imshow('image1',img)
cv2.imshow('image2',img1)
ret,img = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
ret,img1 = cv2.threshold(img1,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
size = np.size(img)
size1 = np.size(img1)
skel = np.zeros(img.shape,np.uint8)
skel1 = np.zeros(img1.shape,np.uint8)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
img = 255 - img
img1 = 255 - img1
img = cv2.dilate(img,element,iterations=8)
img1 = cv2.dilate(img1,element,iterations=8)
done = False
while(not done):
eroded = cv2.erode(img,element)
eroded1 = cv2.erode(img1,element)
temp = cv2.dilate(eroded,element)
temp1 = cv2.dilate(eroded1,element)
temp = cv2.subtract(img,temp)
temp1 = cv2.subtract(img1,temp1)
skel = cv2.bitwise_or(skel,temp)
skel1 = cv2.bitwise_or(skel1,temp1)
img = eroded.copy()
img1 = eroded1.copy()
zeros = size - cv2.countNonZero(img)
if zeros==size:
done = True
cv2.imshow('IMAGE',skel)
cv2.imshow('TEMPLATE',skel1)
cv2.imwrite("image.jpg",skel)
if cv2.waitKey(0) & 0xFF == ord('q'):
cv2.destroyAllWindows()
This is the code that i tried to convert two grayscale image to two skeletized image using the method of binarization and thinning and the result is also obtained. Now with these two skeletized image , i want to do a comparison to see whether they match or not. How can i correlate each other? Do we need to convert this skeletized into 2d array? Can anyone suggest any solution. Thanks in advance.
There are a number of ways you can compare the images to see if they match. The simplest is to do a pixelwise subtraction to create a new image and then sum the pixels in the new image. If they sum to zero you have an exact match. The larger the sum the worse the match.
You will however have a problem using most comparison techniques on a skeletonized image. You take the image and reduce it to skinny little lines that are unlikely to overlap for images that only deviate from each other by a little bit.
With skeletonized images you often need to compare features. For example, identify the points of intersection of the skeleton, and use the location of those points for comparing images. In your sample image you might be able to extract the lines (I see three major ones) and then compare images based on the location of the lines.
Binary images are already represented as 2D numpy arrays.
This is a complex problem. You can do this by reshaping the images to two vectors (assuming they are exactly the same size), and then calculating the correlation coefficient:
np.corrcoef(img.reshape(-1), img1.reshape(-1))
One possible solution would be to correlate (or subtract) the blurred version of each skeletonized image with one another.
That way, the unavoidable little offsets between skeleton lines wouldn't have such a negative impact on the outcome as if you subtracted the skeletons directly (since the skeleton lines would most probably not overlay exactly over one another).
I'm assuming here that the original images weren't similar to each other in the first place, otherwise you wouldn't need to skeletonize them, right?