How do I combining two or more images in Matlab? - 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)].

Related

Superimposing Multiple Images + Adding Colormap

I'm an undergrad student working in a cell biology lab with a basic background in matlab. I'm working on a project of tracking cell trajectory (time lapse) on a petri dish. Below are two example images that i used the watershed feature to separate from the background. The original pictures had neon green cells, now this is all in black and white/
Let's say i have 20 pictures like this, how might I superimpose one on top of another so they all of equal transparency?
Then, how can i add a colormap that represents time? (The bottom most picture is one end of the colormap and the most recent picture is the opposite end) <- this is extremely challenging as it often things the background is black and not NaN
The Basic Idea
Probably the easiest way to do this, is to take the binary image for each layer, and multiply the image by the time at which it was acquired (or it's index in time). Then you can concatenate all images along the third dimension (using cat). You can compute the maximum value along the third dimension using max. This will make the newer time points appear to be "on top" of the older time points. You can then display the resulting flattened matrix using imagesc and it will automatically map to the colormap for the current figure. Typically we would refer to this as a maximum intensity projection.
Creating Some Data
First since you've only provided two images, I'm going to create some shifted versions of the first image you've provided for the demonstration.
% Create some pseudo-data in a cell array that represents the image over time
im = imread('http://i.imgur.com/xTurvfO.jpg');
im = im(:,:,1);
ims = cell(1, 5);
% Create some shifted versions of im1
shifts = round(linspace(0,1000,5));
for k = 1:numel(shifts)
ims{k} = circshift(im > 100, shifts([k k]));
end
Implementing the Method
Now for the application of the method I discussed
% For each image, multiply the binary mask by the time
for k = 1:numel(ims)
ims{k} = ims{k} * k;
end
% Concatenate all images along the third dimension
IMS = cat(3, ims{:});
% Flatten by taking the maximum value along the third dimension
MIP = max(IMS, [], 3);
% Display the resulting flattened image using imagesc
imagesc(MIP);
% Create a custom colormap with black at the end to create our black background
colormap(cat(1, [0 0 0], parula))
The Result
I have used imfuse to create composite images, which is similar to combining multiple channels on a fluorescent microscope. The Mathworks documentation is http://www.mathworks.com/help/images/ref/imfuse.html.
The tricky part is choosing the vector for color channels. For example, [2,1,2] means choosing B(lue) for image 1, R(ed) and G(reen) for image 2. [2,1,2] is the scheme recommended for colorblind people and gives figure on the left of this image. Using [1,0,2] for red/blue gives the the figure on the right.
fig1 = imread([basepath filesep 'fig.jpg']); %white --> black
fig2 = imread([basepath filesep 'fig2.jpg']);
fig_overlay = imfuse(fig1, fig2,'falsecolor','Scaling','joint', 'ColorChannels', [1,0,2]);
imshow(fig_overlay)

plot polar grey values in matrix without interpolating every for loop

I have a matrix with grey values between 0 and 1. For every entry in the matrix, there are certain polar coordinates that indicate the position of the grey values. I already have either Theta and Rho values (polar) ,both in separate 512×960 matrices. And grayscale values (in a matrix called C) for every Theta and Rho combination. I have the same for X and Y, as I just use pol2cart for the transformation. The problem is that I cannot directly plot these values, as they do not yet fit in the 'bins' of the new matrix.
What I want: to put the grey values in a square matrix of size 1024×1024. I cannot do this directly, because the polar coordinates fall in between the grid of this matrix. Therefore, we now use interpolation, but this is extremely time consuming and has to be done separately for every dataset, although the transformation from the original matrices to this final one will always be the same. Therefore, I'd like to solve this matrix once (either analytically or numerically) and use a matrix multiplication or something similar to apply the manipulation efficiently in every cycle of the code.
One example of what one of these transformations could look like this:
The zeros in the first matrix are the grid, and the value 1 (in between the grid) is the grey value that falls in between four grid points, then I'd like to transform to the second matrix (don't mind the visual spacing between the points).
For every dataset, I have hundreds of these matrices, so I would like to make the code more efficient.
Background: I'm using TriScatteredInterp now for the interpolation. We tried scatteredInterpolant as well, but that is slower. I also posted a related question, but decided to split the two possible solutions, because the solution I ask for here is also applicable to non-MATLAB code and will probably be faster and makes for a smoother (no continuous popping up of figures) execution of the code.
Using the image processing toolbox
Images work a bit differently than the data you have. However, it's fairly straightforward to map one representation into the other.
There is only one problem I see: wrapping. Obviously, θ = 2π = 0, but MATLAB does not know that. AFAIK, there is no easy way to tell MATLAB that.
Why does this matter? Well, simply put, inter-pixel interpolation uses information from the nearest N neighbors to find intermediate colors, with N depending on the interpolation kernel. When doing this somewhere in the middle of the image there is no problem, but at the edges MATLAB has to know that the left edge equals the right edge. This is not standard image processing, and I'm not aware of any function that is capable of this.
Implementation
Now, when disregarding the wrapping problem, this is one way to do it:
function resize_polar()
%% ORIGINAL IMAGE
% ==========================================================================
% Some random greyscale data
C = double(rgb2gray(imread('stars.png')))/255;
% Your current size, and desired size
sz_x = size(C,2); new_sz_x = 1024;
sz_y = size(C,1); new_sz_y = 1024;
% Ranges for teat and rho;
% replace with your actual values
rho_start = 0; theta_start = 0;
rho_end = 10; theta_end = 2*pi;
% Generate regularly spaced grid;
theta = linspace(theta_start, theta_end, sz_x);
rho = linspace(rho_start, rho_end, sz_y);
[theta, rho] = meshgrid(theta,rho);
% Make plot of generated data
plot_polar(theta, rho, C, 'Original image');
% Resize data
[theta,rho,C] = resize_polar_data(theta, rho, C, [new_sz_y new_sz_x]);
% Make plot of generated data
plot_polar(theta, rho, C, 'Rescaled image');
end
function [theta,rho,data] = resize_polar_data(theta,rho,data, new_dims)
% Create fake RGB image cube
IMG = cat(3, theta,rho,data);
% Rescale as if theta and rho are RG color data in the RGB
% image cube
IMG = imresize(IMG, new_dims, 'nearest');
% Split up the data again
theta = IMG(:,:,1);
rho = IMG(:,:,2);
data = IMG(:,:,3);
end
function plot_polar(theta, rho, data, label)
[X,Y] = pol2cart(theta, rho);
figure('renderer', 'opengl')
clf, hold on
surf(X,Y,zeros(size(X)), data, ...
'edgecolor', 'none');
colormap gray
title(label);
end
The images used and plotted:
Le awesomely-drawn 512×960 PNG image
Now, the two look the same (couldn't really come up with a better-suited image), so you'll have to believe me that the 512×960 has indeed been rescaled to 1024×1024, with nearest-neighbor interpolation.
Here are some timings for the actual imresize() operation for some simple kernels:
nearest : 0.008511 seconds.
bilinear: 0.019651 seconds.
bicubic : 0.025390 seconds. <-- default kernel
But this depends strongly on your hardware; I believe imresize offloads a lot of work to the GPU, so if you have a crappy one, it'll be slower.
Wrapping
If the wrapping problem is really important to you, you can modify the function above to do the following:
first, rescale the image with imresize() like before
horizontally concatenate the second half of the grayscale data and the first half. Meaning, you swap the first and second halves to make the left and right edges (0 and 2π) touch in the middle.
rescale this intermediate image with imresize()
Extract the central vertical strip of the rescaled intermediate image
split that up in two equal-width strips
and replace the edge strips of the output image with the two strips you just created
Now, this is kind of a brute force approach: you are re-scaling an image twice, and most of the pixels of the second image round will be discarded. If performance is a problem, you can of course apply the rescale to only the central strip of that intermediate image. But, well, that will be a bit more complicated.

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

fusing more than 2 images in matlab

In MATLAB, how do I fuse more than two images? For example, I want to do what imfuse does but for more than 2 images. Using two images, this is the code I have:
A = imread('file1.jpg');
B = imread('file2.jpg');
C = imfuse(A,B,'blend','Scaling','joint');
C will be fused version of A and B. I have about 50 images to fuse. How do I achieve this?
You could write a for loop, then simply have a single image that stores all of the fused results and repeatedly fusing this image with a new image you read in. As such, let's say your images were named from file1.jpg to file50.jpg. You could do something like this:
A = imread('file1.jpg');
for idx = 2 : 50
B = imread(['file' num2str(idx) '.jpg']); %// Read in the next image
A = imfuse(A, B, 'blend', 'Scaling', 'joint'); %// Fuse and store into A
end
What the above code will do is that it will repeatedly read in the next image, and fuse it with the image stored in A. At each iteration, it will take what is currently in A, fuse it with a new image, then store it back in A. That way, as we keep reading in images, we will keep fusing new images on top of those images that were fused from before. After this for loop finishes, you will have 50 images that are all fused together.
imfuse with the 'blend' method performs alpha blending on two images. In the absence of an alpha channel on the images, this is nothing more than the arithmetic mean of each pair of corresponding pixels. Therefore, one way of interpreting the fusion of N images is to simply average N corresponding pixels, one from each image, to get the output image.
Assuming that:
All images are of size imgSize (e.g., [480,640])
All images have the same pixel value range (e.g., 0-255 for uint8 or 0-1 for double)
the following should give you something reasonable:
numImages = 50;
A = zeros(imgSize,'double');
for idx = 1:numImages
% Borrowing rayryeng's nice filename construction
B = imread(['file' num2str(idx) '.jpg']);
A = A + double(B);
end
A = A/numImages;
The result will be in the array A with type double after the loop and may need to be cast back to the proper type for your image.
Piggy-backing on rayryeng's solution:
What you want to do is increase the alpha at every step in proportion to how much that image is contributing to the already stored images. For Example:
Adding 1 image to 1 existing image, you would want an alpha of 0.5 so that they are equal.
Now adding one image to the 2 existing images, it should contribute 33% to the image and therefore an alpha of 0.33. 4th image should contribute 25% (Alpha=0.25) and so on.
The result follows an x^-1 trend. So at the 20th image, 1/20 = 0.05, so an alpha of 0.05 would be necessary.

Color Comparison of two images using 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, :);