Color Comparison of two images using matlab - matlab

Is it possible to compare the color of two images using Matlab if the two images are of different sizes?The problem that am facing is that, i want to detect the presence of a colored patch in an image?

You could just compare normalized histograms (i.e., like a color probability distribution). If the large and small images are semantically identical, then their normalized histograms are similar.
If they are semantically different, then their histograms will likely differ.

Do you have the image processing toolbox? If so, you might approach the problem by taking the images, splitting them into their component color channels, resizing the individual channels, and re-assembling them into resized color images. I wrote a program to do that a while ago, and I recall the code looking something like this:
function imout = ResizeRGB(imin,height,width)
imout = zeros(height,width,3);
iminR = imin(:,:,1);
iminG = imin(:,:,2);
iminB = imin(:,:,3);
imoutR = imresize(iminR, [height width]);
imoutG = imresize(iminG, [height width]);
imoutB = imresize(iminB, [height width]);
imout(:,:,1) = imoutR;
imout(:,:,2) = imoutG;
imout(:,:,3) = imoutB;
(Since I don't have the IPT handy at the moment, that program should be considered pseudocode even though it's more or less in correct matlab syntax. I can't run it without the IPT, so I can't tell if it's buggy or not.)
Once you resize the images so that they have common dimensions, the problem becomes identical to the problem of comparing colors for two images of equal dimensions.
On the other hand, if you have a picture of the patch and a picture that may contain the patch, you might consider using a binary mask to threshold the results of a cross-correlation (xcorr2 in the IPT). For more information on that approach, there's a tutorial on the MathWorks website: http://www.mathworks.com/products/demos/image/cross_correlation/imreg.html

This would be a bit crude, but you could crop your images to the minimum common size if this will be sufficient for your application:
A = imread("image1.jpg");
B = imread("image2.jpg");
rows = min(size(A,1), size(B,1));
cols = min(size(A,2), size(B,2));
croppedA = A(1:rows, 1:cols, :);
croppedB = B(1:rows, 1:cols, :);

Related

How do I combining two or more images in Matlab?

I need to combine several images (of different textures) together. I have tried the following code:
% Read 4d data
I1 = importdata('Img1.tif');
I2 = importdata('Img2.tif');
% Extract a slice of the data
extractImg1 = I1(:,:,1);
extractImg2 = I2(:,:,1);
% compute image size
[ny1, nx1] = size(extractA1);
[ny2, nx2] = size(extractA2);
P1 = extractImg1 (round(ny1/2)-120:round(ny1/2)+120, round(nx1/2)-120:round(nx1/2)+120);
figure, imshow(P1); title('Img1');
P2 = extractImg2 (round(ny2/2)-120:round(ny2/2)+120, round(nx2/2)-120:round(nx2/2)+120);
figure, imshow(P2); title('Img2');
Please, what should I do next?
Secondly, the combined image will be needed for laser printing. The images do not have exactly the same pixel dimensions thus; I was told that it would not make sense to combine them, as this might slightly reduce accuracy.
Nonetheless, I still have a feeling that combining the images wouldn’t be wrong considering that they all have the same resolutions.
I need advice as to whether I should go ahead with the combination. Many thanks in advance.
You have extracted two equal-sized regions from the two images. If you want to put those side-by-side in the same image, use cat, or equivalently, use the square brackets []:
next_to_each_other = [P1,P2];
on_top_of_each_other = [P1;P2];
But note that you can put these things together even if they don't have the same sizes. For example, if I1 is NxM pixels, and I2 is NxK (with N the vertical size as customary in MATLAB) then you can still do [I1,I2] because the vertical size matches.
If nether the vertical nor horizontal sizes match, you can pad one with zeros (or whatever value is appropriate) using padarray before putting them together:
ny1 = size(I1,1);
ny2 = size(I2,1);
if ny1<ny2
I1 = padarray(I1,[ny2-ny1,0,0],0,'post'); % The 0 is the value to pad
elseif ny2<ny1
I2 = padarray(I2,[ny1-ny2,0,0],0,'post'); % The 0 is the value to pad
end
out = [I1,I2];
padarray also allows replicating the data in the matrix instead of padding with zeros. Read the documentation to find what is appropriate. padarray requires the Image Processing Toolbox. If you don't have it, you can replicate its functionality by creating an array with zeros of the appropriate size using the zeros function, and adding it to the image using something like [I1;zeros(ny2-ny1,size(I1,2),size(I1,3)].

Techniques for detecting small blobs in noisy images

I am trying to write a program that uses computer vision techniques to detect (and track) tiny blobs in a stream of very noisy images. The image stream comes from an dual X ray imaging setup, which outputs left and right views (different sizes because of collimating differently). My data is of two types: one set of images are not so noisy, which I am just using to try different techniques with, and the other set are noisier, and this is where the detection needs to work at the end. The image stream is at 60 Hz. This is an example of a raw image from the X ray imager:
Here are some cropped out samples of the regions of interest. The blobs that need to be detected are the small black spots near the center of the image.
Initially I started off with a simple contour/blob detection techniques in OpenCV, which were not very helpful. Eventually I moved on to techniques such as "opening" the image using morphological operators, and subsequently performing a Laplacian of Gaussian blob detection to detect areas of interest. This gave me better results for the low-noise versions of the images, but fails when it comes to the high-noise ones: gives me too many false positives. Here is a result from a low-noise image (please note input image was inverted).
The code for my current LoG based approach in MATLAB goes as below:
while ~isDone(videoReader)
frame = step(videoReader);
roi_frame = imcrop(frame, [660 410 120 110]);
I_roi = rgb2gray(roi_frame);
I_roi = imcomplement(I_roi);
I_roi = wiener2(I_roi, [5 5]);
background = imopen(I_roi,strel('disk',3));
I2 = imadjust(I_roi - background);
K = imgaussfilt(I2, 5);
level = graythresh(K);
bw = im2bw(I2);
sigma = 3;
% Filter image with LoG
I = double(bw);
h = fspecial('log',sigma*30,sigma);
Ifilt = -imfilter(I,h);
% Threshold for points of interest
Ifilt(Ifilt < 0.001) = 0;
% Dilate to obtain local maxima
Idil = imdilate(Ifilt,strel('disk',50));
% This is the final image
P = (Ifilt == Idil) .* Ifilt;
Is there any way I can improve my current detection technique to make it work for images with a lot of background noise? Or are there techniques better suited for images like this?
The approach I would take:
-Average background subtraction
-Aggressive Gaussian smoothing (this filter should be shaped based on your target object, off the top of my head I think you want the sigma about half the smallest cross section of your object, but you may want to fiddle with this) Basically the goal is blurring the noise as much as possible without completely losing your target objects (based on shape and size)
-Edge detection. Try to be specific to the object if possible (basically, look at what the object's edge looks like after Gaussian smoothing and set your edge detection to look for that width and contrast shift)
-May consider running a closing operation here.
-Search the whole image for islands (fully enclosed regions) filter based on size and then on shape.
I am taking a hunch that despite the incredibly low signal to noise ratio, your granularity of noise is hopefully significantly smaller than your object size. (if your noise is both equivalent contrast and same ballpark size as your object... you are sunk and need to re-evaluate your acquisition imo)
Another note based on your speed needs. Extreme amounts of processing savings can be made through knowing last known positions and searching locally and also knowing where new targets can enter the image from.

Matlab : How to check if two images are similar to each other

I have coloured images of size 20 by 20. The objective is that :
based on a query, I need to check which recalled image is the closest match to the query. For example, let 10 images be the recalled ones. Out of the 10 recalled images, I need to find the closest match to the query.
I was thinking of using the correlation between the images. One can use the Correlation coefficient - higher the value, more is the correlation between pixel values. (Please correct me where wrong).
R = corr2(A,B1) will compute the correlation coefficient between A and B where A is the query, B1 is the first recalled image image of the same size. I used the above command for colored images but I got the result R = NaN. How do I solve this problem for colored and gray scale. Thank you.
This is the QUERY IMAGE
The other image(recalled / retrieved B1)
UPDATE : Code for testing correlation of an image with itself from a databasae called patches.mat (patches is the database. It consists of 59500 20x20 patches, reshaped into 400-dimensional column vectors,
taken from a bunch of motorcycle images; I am using the 50 th example as the query image)
img_query = imagesc(reshape(patches(:,50),20,20));
colormap gray;axis image;
R = corr2(img_query,img_query)
Answer = NaN
That is because one of the images is black or includes a single color, meaning that all the values of the matrix are similar. Check the following examples:
I = imread('pout.tif');
J = I*0; % create a black image
R = corr2(I,J);
R =
NaN
I = imread('pout.tif');
J = 255*ones(size(I)); % create a white image
R = corr2(I,J);
R =
NaN
Update
It should work in your case, as you can see in the following example, it works perfectly:
I1 = abs(255*(rand(10,10));
I2 = abs(255*(rand(10,10));
corr2(I1,I2)
ans =
0.0713
Even with the images you have shared, it is working for me. To find out your problem, you have to either share a part of your code, or post images as they are, not saved images (with a size 420x560x3).
Note: you cannot have images including more than 1 layer.
Your code shows that you are using the handle of the image instead of the image itself.
Test this:
I = reshape(patches(:,50),20,20);
corr2(I,I)
I would try also the Universal Quality Index by Wang which gives you a 1.0 if both images are equal, and less in other cases with spatial indication where they differ, think of one image as reference, the other as a degraded one relative to the first one. See http://www.cns.nyu.edu/~zwang/files/research/quality_index/demo.html

Detection of homogeneous area in term of connectivity in image

I am looking for some measurements to do to distinct between these two binary images (texte and noise).
Hough transform of the frequency domain don't tell me much (either in skeleton or in the original shape), as can be seen below !
in the spatial domain, I have try to measure, if a given pixel participate to line or curve, or participate to a random shape, and then measures the percentage of all pixels participating and not participating to normal shape (lines and curves) to distinguish between these images, but I didn't succeed, in implementation.
what do you think ?
I use matlab for test.
Thanks in advance
Looking at the skeleton images, one could notice how the noise image has lots of branches in it, as compared to the text image and this looks like one of the features that could be exploited. The experiment as code shown below soughts to verify the same, using the OP's images -
Experiment Code
%%// Experiment to research what features what might help us
%%// differentiate betwen noise and text images
%%// Read in the given images
img1 = imread('noise.png');
img2 = imread('text.png');
%%// Since the given images had the features as black and rest as white,
%%// we must invert them
img1 = ~im2bw(img1);
img2 = ~im2bw(img2);
%%// Remove the smaller blobs from both of the images which basically
%%// denote the actual noise in them
img1 = rmnoise(img1,60);
img2 = rmnoise(img2,60);
%// Get the skeleton images
img1 = bwmorph(img1,'skel',Inf);
img2 = bwmorph(img2,'skel',Inf);
%%// Find blobs branhpoints for each blob in both images
[L1, num1] = bwlabel(img1);
[L2, num2] = bwlabel(img2);
for k = 1:num1
img1_bpts_count(k) = nnz(bwmorph(L1==k,'branchpoints'));
end
for k = 1:num2
img2_bpts_count(k) = nnz(bwmorph(L2==k,'branchpoints'));
end
%%// Get the standard deviation of branch points count
img1_branchpts_std = std(img1_bpts_count)
img2_branchpts_std = std(img2_bpts_count)
Note: Above code uses a function - rmnoise shown below that is built based on the problem discussed at this link :
function NewImg = rmnoise(Img,threshold)
[L,num] = bwlabel( Img );
counts = sum(bsxfun(#eq,L(:),1:num));
B1 = bsxfun(#eq,L,permute(find(counts>threshold),[1 3 2]));
NewImg = sum(B1,3)>0;
return;
Output
img1_branchpts_std =
73.6230
img2_branchpts_std =
12.8417
One can see the big difference between the standard deviations of the two input images, suggesting this feature could be used.
Runs on some other samples
To make our theory a bit more concrete, let's use a pure text image and gradually add noise and see if the standard deviation of branch-points, naming it as check_value suggest anything on them.
(I) Pure text image
check_value = 1.7461
(II) Some added noise image
check_value = 30.1453
(III) Some more added noise image
check_value = 54.6446
Conclusion: As can be seen, this parameter provides quite a good indicator to decide on the nature of images.
Finalized Code
A script could be written to test for whether another input image would be a text or noise one, like this -
%%// Parameters
%%// 1. Decide this based on the typical image size and count of pixels
%%// in the biggest noise blob
rmnoise_threshold = 60;
%%// 2. Decide this based on the typical image size and how convoluted the
%%// noisy images are
branchpts_count_threshold = 50;
%%// Actual processing
%%// We are assuming input images as binary images with features as true
%%// and false in rest of the region
img1 = im2bw(imread(FILE));
img1 = rmnoise(img1,rmnoise_threshold);
img1 = bwmorph(img1,'skel',Inf);
[L1, num1] = bwlabel(img1);
for k = 1:num1
img1_bpts_count(k) = nnz(bwmorph(L1==k,'branchpoints'));
end
if std(img1_bpts_count) > branchpts_count_threshold
disp('This is a noise image');
else
disp('This is a text image');
end
And now what you suggest if we try to use the original shape instead of the skeleton, (to avoid the loss of information).
I try to measure for a given pixel, the elongation of the strokes (instead of straight branches) that past throughout that pixel, by counting the number of transitions from white to black in a clockwise.
I am thinking to use a circle with a radius, and for the origin the pixel in consideration, and store the pixels locating at the edge of the circle in an ordered list (clockwise) and then compute the number of transitions (black to white) from this list.
by increasing the radius of the circle we could trace the shape of elongated stokes and know his orientation.
this is a schema illustrating this.
the pixels that have a number of transitions equal to 0 or bigger than 2 (red ones) have to be classified as noise, and those that have 2 or 1 transition classified as normal.
What do you think of this approach !

Image similarity by Euclidean distance in hsv color space in MATLAB

The code included below calculates the Euclidean distance between two images in hsv color space and if the result is under a Threshold (here set to 0.5) the two images are similar and it will group them in one cluster.
This will be done for a group of images (video frames actually).
It worked well on a group of sample images but when I change the sample it starts to work odd, e.g the result is low for two different images and high (like 1.2) for two similar images.
For example the result for these two very similar images is relatively high: first pic and second pic when it actually should be under 0.5.
What is wrong?
In the code below, f is divided by 100 to allow comparison to values near 0.5.
Im1 = imread('1.jpeg');
Im2 = imread('2.jpeg');
hsv = rgb2hsv(Im1);
hn1 = hsv(:,:,1);
hn1=hist(hn1,16);
hn1=norm(hn1);
hsv = rgb2hsv(Im2);
hn2 = hsv(:,:,1);
hn2=hist(hn2,16);
hn2=norm(hn2);
f = norm(hn1-hn2,1)
f=f/100
These two lines:
hn1=hist(hn1,16);
hn1=norm(hn1);
convert your 2D image into a scalar. I suspect that is not what you're interested in doing.....
EDIT:
Probably a better approach would be:
hn1 = hist(hn1(:),16) / numel(hn1(:));
but, you haven't really given us much on the math, so this is just a guess.