How to overlay several images in Matlab? - image

I have the images A, B and C. How to overlay these images to result in D using Matlab? I have at least 50 images to make it. Thanks.
Please, see images here.
Download images:
A: https://docs.google.com/open?id=0B5AOSYBy_josQ3R3Y29VVFJVUHc
B: https://docs.google.com/open?id=0B5AOSYBy_josTVIwWUN1a085T0U
C: https://docs.google.com/open?id=0B5AOSYBy_josLVRwQ3JNYmJUUFk
D: https://docs.google.com/open?id=0B5AOSYBy_josd09TTFE2VDJIMzQ

To fade the images together:
Well since images in matlab are just matrices, you can add them together.
D = A + B + C
Of course if the images don't have the same dimensions, you will have to crop all the images to the dimensions of the smallest one.
The more you apply this principle, the larger the pixel values are going to get. It might be beneficial to display the images with imshow(D, []), where the empty matrix argument tells imshow to scale the pixel values to the actual minimum and maximum values contained in D.
To replace changed parts of original image:
Create a function combine(a,b).
Pseudocode:
# create empty answer matrix
c = zeros(width(a), height(a))
# compare each pixel in a to each pixel in b
for x in 1..width
for y in 1..height
p1 = a(x,y)
p2 = b(x,y)
if (p1 != p2)
c(x,y) = p2
else
c(x,y) = p1
end
end
end
Use this combine(a,b) function like so:
D = combine(combine(A,B),C)
or in a loop:
D = combine(images(1), images(2));
for i = 3:numImages
D = combine(D, images(i));
end

Judging from the example, it seems to me that the operation requested is a trivial case of "alpha compositing" in the specified order.
Something like this should work - don't have matlab handy right now, so this is untested, but it should be correct or almost so.
function abc = composite(a, b, c)
m = size(a,1); n = size(a,2);
abc = zeros(m, n, 3);
for i=1:3
% Vectorize the i-th channel of a, add it to the accumulator.
ai = a(:,:,i);
acc = ai(:);
% Vectorize the i-th channel of b, replace its nonzero pixels in the accumulator
bi = b(:,:,i);
bi = bi(:);
z = (bi ~= 0);
acc(z) = bi(z);
% Likewise for c
ci = c(:,:,i);
ci = ci(:);
z = (ci ~= 0);
acc(z) = ci(z);
% Place the result in the i-th channel of abc
abc(:,:,i) = reshape(acc, m, n);
end

Related

Efficient way of computing multivariate gaussian varying the mean - Matlab

Is there a efficient way to do the computation of a multivariate gaussian (as below) that returns matrix p , that is, making use of some sort of vectorization? I am aware that matrix p is symmetric, but still for a matrix of size 40000x3, for example, this will take quite a long time.
Matlab code example:
DataMatrix = [3 1 4; 1 2 3; 1 5 7; 3 4 7; 5 5 1; 2 3 1; 4 4 4];
[rows, cols ] = size(DataMatrix);
I = eye(cols);
p = zeros(rows);
for k = 1:rows
p(k,:) = mvnpdf(DataMatrix(:,:),DataMatrix(k,:),I);
end
Stage 1: Hack into source code
Iteratively we are performing mvnpdf(DataMatrix(:,:),DataMatrix(k,:),I)
The syntax is : mvnpdf(X,Mu,Sigma).
Thus, the correspondence with our input becomes :
X = DataMatrix(:,:);
Mu = DataMatrix(k,:);
Sigma = I
For the sizes relevant to our situation, the source code mvnpdf.m reduces to -
%// Store size parameters of X
[n,d] = size(X);
%// Get vector mean, and use it to center data
X0 = bsxfun(#minus,X,Mu);
%// Make sure Sigma is a valid covariance matrix
[R,err] = cholcov(Sigma,0);
%// Create array of standardized data, and compute log(sqrt(det(Sigma)))
xRinv = X0 / R;
logSqrtDetSigma = sum(log(diag(R)));
%// Finally get the quadratic form and thus, the final output
quadform = sum(xRinv.^2, 2);
p_out = exp(-0.5*quadform - logSqrtDetSigma - d*log(2*pi)/2)
Now, if the Sigma is always an identity matrix, we would have R as an identity matrix too. Therefore, X0 / R would be same as X0, which is saved as xRinv. So, essentially quadform = sum(X0.^2, 2);
Thus, the original code -
for k = 1:rows
p(k,:) = mvnpdf(DataMatrix(:,:),DataMatrix(k,:),I);
end
reduces to -
[n,d] = size(DataMatrix);
[R,err] = cholcov(I,0);
p_out = zeros(rows);
K = sum(log(diag(R))) + d*log(2*pi)/2;
for k = 1:rows
X0 = bsxfun(#minus,DataMatrix,DataMatrix(k,:));
quadform = sum(X0.^2, 2);
p_out(k,:) = exp(-0.5*quadform - K);
end
Now, if the input matrix is of size 40000x3, you might want to stop here. But with system resources permitting, you can vectorize everything as discussed next.
Stage 2: Vectorize everything
Now that we see what's actually going on and that the computations look parallelizable, it's time to step-up to use bsxfun in 3D with his good friend permute for a vectorized solution, like so -
%// Get size params and R
[n,d] = size(DataMatrix);
[R,err] = cholcov(I,0);
%// Calculate constants : "logSqrtDetSigma" and "d*log(2*pi)/2`"
K1 = sum(log(diag(R)));
K2 = d*log(2*pi)/2;
%// Major thing happening here as we calclate "X0" for all iterations
%// in one go with permute and bsxfun
diffs = bsxfun(#minus,DataMatrix,permute(DataMatrix,[3 2 1]));
%// "Sigma" is an identity matrix, so it plays no in "/R" at "xRinv = X0 / R".
%// Perform elementwise squaring and summing rows to get vectorized "quadform"
quadform1 = squeeze(sum(diffs.^2,2))
%// Finally use "quadform1" and get vectorized output as a 2D array
p_out = exp(-0.5*quadform1 - K1 - K2)

How do I implement cross-correlation to prove two images of the same scene are similar? [duplicate]

How can I select a random point on one image, then find its corresponding point on another image using cross-correlation?
So basically I have image1, I want to select a point on it (automatically) then find its corresponding/similar point on image2.
Here are some example images:
Full image:
Patch:
Result of cross correlation:
Well, xcorr2 can essentially be seen as analyzing all possible shifts in both positive and negative direction and giving a measure for how well they fit with each shift. Therefore for images of size N x N the result must have size (2*N-1) x (2*N-1), where the correlation at index [N, N] would be maximal if the two images where equal or not shifted. If they were shifted by 10 pixels, the maximum correlation would be at [N-10, N] and so on. Therefore you will need to subtract N to get the absolute shift.
With your actual code it would probably be easier to help. But let's look at an example:
(A) We read an image and select two different sub-images with offsets da and db
Orig = imread('rice.png');
N = 200; range = 1:N;
da = [0 20];
db = [30 30];
A=Orig(da(1) + range, da(2) + range);
B=Orig(db(1) + range, db(2) + range);
(b) Calculate cross-correlation and find maximum
X = normxcorr2(A, B);
m = max(X(:));
[i,j] = find(X == m);
(C) Patch them together using recovered shift
R = zeros(2*N, 2*N);
R(N + range, N + range) = B;
R(i + range, j + range) = A;
(D) Illustrate things
figure
subplot(2,2,1), imagesc(A)
subplot(2,2,2), imagesc(B)
subplot(2,2,3), imagesc(X)
rectangle('Position', [j-1 i-1 2 2]), line([N j], [N i])
subplot(2,2,4), imagesc(R);
(E) Compare intentional shift with recovered shift
delta_orig = da - db
%--> [30 10]
delta_recovered = [i - N, j - N]
%--> [30 10]
As you see in (E) we get exactly the shift we intenionally introduced in (A).
Or adjusted to your case:
full=rgb2gray(imread('a.jpg'));
template=rgb2gray(imread('b.jpg'));
S_full = size(full);
S_temp = size(template);
X=normxcorr2(template, full);
m=max(X(:));
[i,j]=find(X==m);
figure, colormap gray
subplot(2,2,1), title('full'), imagesc(full)
subplot(2,2,2), title('template'), imagesc(template),
subplot(2,2,3), imagesc(X), rectangle('Position', [j-20 i-20 40 40])
R = zeros(S_temp);
shift_a = [0 0];
shift_b = [i j] - S_temp;
R((1:S_full(1))+shift_a(1), (1:S_full(2))+shift_a(2)) = full;
R((1:S_temp(1))+shift_b(1), (1:S_temp(2))+shift_b(2)) = template;
subplot(2,2,4), imagesc(R);
However, for this method to work properly the patch (template) and the full image should be scaled to the same resolution.
A more detailed example can also be found here.

MATLAB vectorization: creating a cell array of neighbor index arrays

I have a logical matrix X of n points, where X(i, j) == 1 if points i and j are neighbors and 0 otherwise.
I would like to create a cell array Y with each entry Y{i} (i from 1 to n) containing an array with the indeces of point i's neighbors.
In other words, I would like to vectorize the following:
n = 10;
X = (rand(n, n) < 0.5);
Y = cell(1, 10);
for i = 1:10
[Y{i}] = find(X(i, :));
end
As one approach you can use accumarray -
[R,C] = find(X.') %//'
Y = accumarray(C(:),R(:),[],#(x) {x})
If you need each cell to be a row vector, you need to add one transpose there with x, like so -
Y = accumarray(C(:),R(:),[],#(x) {x.'})
As another approach, you can also use arrayfun, but I don't think this would be a vectorized solution -
Y = arrayfun(#(n) R(C==n),1:max(C),'Uni',0)
If you don't care about the order of elements in each cell, you can avoid the transpose of X to get R and C like so -
[R,C] = find(X)
Then, interchange the positions of R and C with the accumarray and arrayfun based approaches as listed earlier.
Here's some more voodoo:
Y = mat2cell(nonzeros(bsxfun(#times, X, 1:size(X,1)).').', 1, sum(X,2));
The most important function here is bsxfun. To see how the code works, I suggest you observe partial results from innermost outwards: first bsxfun(#times, X, 1:size(X,1)).', then nonzeros(...), etc.

How to display error map of two binary images by matlab

I have two binary images that refer as ground truth image A and test image B. I want to calculate Dice Coefficient Similarity defined here.
To calculate it is very easy. This is one same code
function dist = dist_Dice(A,B)
% Calculation of the Dice Coefficient
idx_img = find(B== 1);
idx_ref = find(A== 1);
idx_inter = find((B== 1) & (A== 1));
dist = 2*length(idx_inter)/(length(idx_ref)+length(idx_img));
The result is a number. But my work is how to show this result visually by an image. The range of the image from 0 to 1. I have no idea to resolve it? I think it similar the overlap of two images that regions overlap have pixel equal 0 and otherwise equal 1.Could you help me implement in matlab?
I don't know if something like that is close to what you have in mind in terms of visualising the differences. As you pointed out, the quantity in which you are interested is a scalar, so there aren't too many options.
RandStream.setDefaultStream(RandStream('mt19937ar','seed',0)); % For reproducibility of results
a = rand(10);
b = rand(10);
A = im2bw(a, graythresh(a));
subplot(2,2,1)
imshow(A, 'InitialMagnification', 'fit')
title('A (ground truth image)')
B = im2bw(b, graythresh(b));
subplot(2,2,2)
imshow(B, 'InitialMagnification', 'fit')
title('B (test image)')
idx_img = find(B);
idx_ref = find(A);
idx_inter = find(A&B);
common_white = zeros(size(A));
common_white(idx_inter) = 1;
subplot(2,2,3)
imshow(common_white, 'InitialMagnification', 'fit')
title('White in both pictures')
dist = 2*length(idx_inter)/(length(idx_ref)+length(idx_img))
idx_img = find(~B);
idx_ref = find(~A);
idx_inter = find(~A&~B);
common_black = ones(size(A));
common_black(idx_inter) = 0;
subplot(2,2,4)
imshow(common_black, 'InitialMagnification', 'fit')
title('Black in both pictures')
dist = 2*length(idx_inter)/(length(idx_ref)+length(idx_img))
Think you are looking for this -
AB = false(size(A));
AB(idx_inter) = true;
figure, imshow(AB)
Generally, with binary images, note that you don't have to do the ==1 part. Also, if you just need to know how many ones there are in an image, you don't need to use find and then length, you can just sum over a binary image:
AB = A&B
imshow(AB);
dist = 2*sum(AB(:))/(sum(A(:))+sum(B(:)));
I find that (sorry, couldn't resist) m = find(A) is for a 256 x 256 image, about twice as quick as the ==1 equivalent.

Reduce Close Points

input: C matrix 2xN (2D points)
output: C matrix 2xM (2D points) with equal or less points.
Lets say we have C matrix 2xN that contains several 2D points, and it looks something like that:
What we want is to group "close" points to one point, measured by the average of the other points.
For example, in the second image, every group of blue circle will be one point, the point coordinate will be the average point off all points in the blue circle.
also by saying "close", I mean that: their distance one to each other will be smaller then DELTA (known scalar). So wanted output is:
About running time of the algorithm, I don't have upper-limit request but I call that method several times...
What i have tried:
function C = ReduceClosePoints(C ,l_boundry)
x_size = abs(l_boundry(1,1)-l_boundry(1,2)); %220
DELTA = x_size/10;
T = [];
for i=1:size(C,2)
sum = C(:,i);
n=1;
for j=1:size(C,2)
if i~=j %not in same point
D = DistancePointToPoint(C(:,i),C(:,j));
if D < DELTA
sum = sum + C(:,j);
n=n+1;
end
end
end
sum = sum./n; %new point -> save in T matrix
T = [T sum];
end
C = T;
end
I am using Matlab.
Thank you
The simplest way to remove the duplicates from the output is in the final step, by replacing:
C = T;
with:
C = unique(T', 'rows')';
Note that unique() in matrix context only works row-wise, so we have to transpose twice.
I forgot to remove points that i have tested before.
If that code will be useful to someone use that code:
function C = ReduceClosePoints(C ,l_boundry)
x_size = abs(boundry(1,1)-boundry(1,2)); %220 / 190
DELTA = x_size/10;
i=1;
while i~=size(C,2)+1
sum = C(:,i);
n=1;
j=i;
while j~=size(C,2)+1
if i~=j %not same point
D = DistancePointToPoint(C(:,i),C(:,j));
if D < DELTA
sum = sum + C(:,j);
n=n+1;
C(:,j) = [];
j=j-1;
end
end
j=j+1;
end
C(:,i) = sum./n; %change to new point
i=i+1;
end
end

Resources