Calculating differences between many images - image

My problem is one related to image registration. I have a number of images in a .tif-file, all the same size. I read those into MATLAB as a 3D-array of matrices and try to optimize the overlay of features in those images solely by rotation. I tried using imabsdiff, but resorted to just doing it like shown below.
In short, I input a vector containing as many angles as I have images in my stack. I rotate each image in the stack by each corresponding angle. Then, I calculate the absolute differences ([image1-image2] + [image2-image1]) which is what imabsdiff does, but faster. For this, I use two loop variables and compare each individual image to the whole stack, while leaving out comparison between identical images. Cost is the sum of differences between all images.
for oo = 1:slidecount
centered_stack(:,:,oo) = imrotate(centered_stack(:,:,oo),
angle_in(oo), 'bilinear', 'crop');
end
for pp = 1:slidecount
image1 = centered_stack(:,:,pp);
for qq = 1:slidecount
if qq ~= pp % only do this if comparing different images
image2 = centered_stack(:,:,qq);
cost_temp(qq) = sum(sum(abs(image1 - image2))) +
sum(sum(abs(image2 - image1)));
else
cost_temp(qq) = 0;
end
cost_temp = sum(cost_temp);
end
cost(pp) = cost_temp;
end
cost = sum(cost);
This then serves as a cost value for an optimization procedure. Can someone please tell me if there is a faster, maybe vectorized way to do this or something conceptually completely different? This approach gets very time consuming with many images. FFT based registration maybe? Thanks!

In your code you compare each pair of images twice:
image_1 to image_2 (pp == 1, qq == 2)
image_2 to image_1 (pp == 2, qq == 1)
Is this intended? If you make second loop look like this:
for qq = (pp+1):slidecount
you will reduce the computation by the factor of 2. Also your condition for checking qq ~= pp will not be needed anymore.

Related

Global minimum in a huge convex matrix by using small matrices

I have a function J(x,y,z) that gives me the result of those coordinates. This function is convex. What is needed from me is to find the minimum value of this huge matrix.
At first I tried to loop through all of them, calculate then search with min function, but that takes too long ...
so I decided to take advantage of the convexity.
Take a random(for now) set of coordinates, that will be the center of my small 3x3x3 matrice, find the local minimum and make it the center for the next matrice. This will continue until we reach the global minimum.
Another issue is that the function is not perfectly convex, so this problem can appear as well
so I'm thinking of a control measure, when it finds a fake minimum, increase the search range to make sure of it.
How would you advise me to go with it? Is this approach good? Or should I look into something else?
This is something I started myself but I am fairly new to Matlab and I am not sure how to continue.
clear all
clc
min=100;
%the initial size of the search matrix 2*level +1
level=1;
i=input('Enter the starting coordinate for i (X) : ');
j=input('Enter the starting coordinate for j (Y) : ');
k=input('Enter the starting coordinate for k (Z) : ');
for m=i-level:i+level
for n=j-level:j+level
for p=k-level:k+level
A(m,n,p)=J(m,n,p);
if A(m,n,p)<min
min=A(m,n,p);
end
end
end
end
display(min, 'Minim');
[r,c,d] = ind2sub(size(A),find(A ==min));
display(r,'X');
display(c,'Y');
display(d,'Z');
Any guidance, improvement and constructive criticism are appreciated. Thanks in advance.
Try fminsearch because it is fairly general and easy to use. This is especially easy if you can specify your function anonymously. For example:
aFunc = #(x)100*(x(2)-x(1)^2)^2+(1-x(1))^2
then using fminsearch:
[x,fval] = fminsearch( aFunc, [-1.2, 1]);
If your 3-dimensional function, J(x,y,z), can be described anonymously or as regular function, then you can try fminsearch. The input takes a vector so you would need to write your function as J(X) where X is a vector of length 3 so x=X(1), y=X(2), z=X(3)
fminseach can fail especially if the starting point is not near the solution. It is often better to refine the initial starting point. For example, the code below samples a patch around the starting vector and generally improves the chances of finding the global minimum.
% deltaR is used to refine the start vector with scatter min search over
% region defined by a path of [-deltaR+starVec(i):dx:deltaR+startVec(i)] on
% a side.
% Determine dx using maxIter.
maxIter = 1e4;
dx = max( ( 2*deltaR+1)^2/maxIter, 1/8);
dim = length( startVec);
[x,y] = meshgrid( [-deltaR:dx:deltaR]);
xV = zeros( length(x(:)), dim);
% Alternate patches as sequential x-y grids.
for ii = 1:2:dim
xV(:, ii) = startVec(ii) + x(:);
end
for ii = 2:2:dim
xV(:, ii) = startVec(ii) + y(:);
end
% Find the scatter min index to update startVec.
for ii = 1: length( xV)
nS(ii)=aFunc( xV(ii,:));
end
[fSmin, iw] = min( nS);
startVec = xV( iw,:);
fSmin = fSmin
startVec = startVec
[x,fval] = fminsearch( aFunc, startVec);
You can run a 2 dimensional test case f(x,y)=z on AlgorithmHub. The app is running the above code in Octave. You can edit the in-line function (possibly even try your problem) from this web-site as well.

How to average parameters for a grid in utm format avoiding for loops [duplicate]

This question already has an answer here:
matlab: splitting small arrays by latitude/longitude into individual grid cells of one large array
(1 answer)
Closed 7 years ago.
Hi I have a small problem. I have 1 sec time resolution gps data in utm (x,y) with speed for one year and I would like to make speed averages over a 20m grid. My code works but it is really slow as i use for loops to find the coordinates which matches the grid. Any help is appreciated.
kind regards matthias
%x_d is x coordinate
%Y_d is y coordinate
%x_vec is the xgrid vector definition
%y_vec is the ygrid vector definition
%s is the speed
for i=1:length(vec_x)
for j=1:length(vec_y)
ind = find(x_d<=vec_x(i)+10& x_d>vec_x(i)-10 & y_d<=vec_y(j)+10 & y_d>vec_y(j)-10);
Ad(j,i) = nanmean(s(ind));
end
end
It can be done with no loops using MATLAB's histcounts and accumarray functions. This question/solution is a near duplicate of this question/solution, except for possibly the use of histcounts.
histcounts is good for binning problems (which this is). [~,~,x_idx]=histcounts(x_d,x_vec) tells you which x-bin each x-coordinate is in. Similarly for y_d, y_vec.
accumarray is good for summing with repeated indices (to avoid looping). The call below sums the speed values for each bin, and then applies the #mean function to average them. The 0 tells accumarray to fill empty bins with zeros.
x_vec = 0:20;
y_vec = 0:20;
x_d = rand(1000,1)*20;
y_d = rand(1000,1)*20;
s = rand(1000,1);
[~,~,x_idx] = histcounts(x_d,x_vec);
[~,~,y_idx] = histcounts(y_d,y_vec);
avg = accumarray([x_idx y_idx],s,[length(x_vec)-1,length(y_vec)-1],#mean,0)
A) Use logical indexing, which gets rid of the time consuming find: Your code
ind = find(x_d<=vec_x(i)+10& x_d>vec_x(i)-10 & y_d<=vec_y(j)+10 & y_d>vec_y(j)-10);
Ad(j,i) = nanmean(s(ind));
is equal to the faster
ix = x_d<=vec_x(i)+10& x_d>vec_x(i)-10 & y_d<=vec_y(j)+10 & y_d>vec_y(j)-10;
Ad(j,i) = nanmean(s(ix));
B) Try to use your known Grid-size information to access the right grid-element directly. From the offset and element-size (20) you can infer:
ind_x = floor((x_d - min(vec_x))./20) + 1;
ind_y = floor((y_d - min(vec_y))./20) + 1;
Then you would loop throught your grid and pick the positions. Maybe this could be improved by arrayfun.
for i=1:length(vec_x)
for j=1:length(vec_y)
ix = ind_x == i & ind_y == j;
Ad(j,i) = nanmean(s(ix));
end
end

matlab code optimization - clustering algorithm KFCG

Background
I have a large set of vectors (orientation data in an axis-angle representation... the axis is the vector). I want to apply a clustering algorithm to. I tried kmeans but the computational time was too long (never finished). So instead I am trying to implement KFCG algorithm which is faster (Kirke 2010):
Initially we have one cluster with the entire training vectors and the codevector C1 which is centroid. In the first iteration of the algorithm, the clusters are formed by comparing first element of training vector Xi with first element of code vector C1. The vector Xi is grouped into the cluster 1 if xi1< c11 otherwise vector Xi is grouped into cluster2 as shown in Figure 2(a) where codevector dimension space is 2. In second iteration, the cluster 1 is split into two by comparing second element Xi2 of vector Xi belonging to cluster 1 with that of the second element of the codevector. Cluster 2 is split into two by comparing the second element Xi2 of vector Xi belonging to cluster 2 with that of the second element of the codevector as shown in Figure 2(b). This procedure is repeated till the codebook size is reached to the size specified by user.
I'm unsure what ratio is appropriate for the codebook, but it shouldn't matter for the code optimization. Also note mine is 3-D so the same process is done for the 3rd dimension.
My code attempts
I've tried implementing the above algorithm into Matlab 2013 (Student Version). Here's some different structures I've tried - BUT take way too long (have never seen it completed):
%training vectors:
Atgood = Nx4 vector (see test data below if want to test);
vecA = Atgood(:,1:3);
roA = size(vecA,1);
%Codebook size, Nsel, is ratio of data
remainFrac2=0.5;
Nseltemp = remainFrac2*roA; %codebook size
%Ensure selected size after nearest power of 2 is NOT greater than roA
if 2^round(log2(Nseltemp)) &lt roA
NselIter = round(log2(Nseltemp));
else
NselIter = ceil(log2(Nseltemp)-1);
end
Nsel = 2^NselIter; %power of 2 - for LGB and other algorithms
MAIN BLOCK TO OPTIMIZE:
%KFCG:
%%cluster = cell(1,Nsel); %Unsure #rows - Don't know how to initialize if need mean...
codevec(1,1:3) = mean(vecA,1);
count1=1;
count2=1;
ind=1;
for kk = 1:NselIter
hh2 = 1:2:size(codevec,1)*2;
for hh1 = 1:length(hh2)
hh=hh2(hh1);
% for ii = 1:roA
% if vecA(ii,ind) &lt codevec(hh1,ind)
% cluster{1,hh}(count1,1:4) = Atgood(ii,:); %want all 4 elements
% count1=count1+1;
% else
% cluster{1,hh+1}(count2,1:4) = Atgood(ii,:); %want all 4
% count2=count2+1;
% end
% end
%EDIT: My ATTEMPT at optimizing above for loop:
repcv=repmat(codevec(hh1,ind),[size(vecA,1),1]);
splitind = vecA(:,ind)&gt=repcv;
splitind2 = vecA(:,ind)&ltrepcv;
cluster{1,hh}=vecA(splitind,:);
cluster{1,hh+1}=vecA(splitind2,:);
end
clear codevec
%Only mean the 1x3 vector portion of the cluster - for centroid
codevec = cell2mat((cellfun(#(x) mean(x(:,1:3),1),cluster,'UniformOutput',false))');
if ind &lt 3
ind = ind+1;
else
ind=1;
end
end
if length(codevec) ~= Nsel
warning('codevec ~= Nsel');
end
Alternatively, instead of cells I thought 3D Matrices would be faster? I tried but it was slower using my method of appending the next row each iteration (temp=[]; for...temp=[temp;new];)
Also, I wasn't sure what was best to loop with, for or while:
%If initialize cell to full length
while length(find(~cellfun('isempty',cluster))) < Nsel
Well, anyways, the first method was fastest for me.
Questions
Is the logic standard? Not in the sense that it matches with the algorithm described, but from a coding perspective, any weird methods I employed (especially with those multiple inner loops) that slows it down? Where can I speed up (you can just point me to resources or previous questions)?
My array size, Atgood, is 1,000,000x4 making NselIter=19; - do I just need to find a way to decrease this size or can the code be optimized?
Should this be asked on CodeReview? If so, I'll move it.
Testing Data
Here's some random vectors you can use to test:
for ii=1:1000 %My size is ~ 1,000,000
omega = 2*rand(3,1)-1;
omega = (omega/norm(omega))';
Atgood(ii,1:4) = [omega,57];
end
Your biggest issue is re-iterating through all of vecA FOR EACH CODEVECTOR, rather than just the ones that are part of the corresponding cluster. You're supposed to split each cluster on it's codevector. As it is, your cluster structure grows and grows, and each iteration is processing more and more samples.
Your second issue is the loop around the comparisons, and the appending of samples to build up the clusters. Both of those can be solved by vectorizing the comparison operation. Oh, I just saw your edit, where this was optimized. Much better. But codevec(hh1,ind) is just a scalar, so you don't even need the repmat.
Try this version:
% (preallocs added in edit)
cluster = cell(1,Nsel);
codevec = zeros(Nsel, 3);
codevec(1,:) = mean(Atgood(:,1:3),1);
cluster{1} = Atgood;
nClusters = 1;
ind = 1;
while nClusters < Nsel
for c = 1:nClusters
lower_cluster_logical = cluster{c}(:,ind) < codevec(c,ind);
cluster{nClusters+c} = cluster{c}(~lower_cluster_logical,:);
cluster{c} = cluster{c}(lower_cluster_logical,:);
codevec(c,:) = mean(cluster{c}(:,1:3), 1);
codevec(nClusters+c,:) = mean(cluster{nClusters+c}(:,1:3), 1);
end
ind = rem(ind,3) + 1;
nClusters = nClusters*2;
end

Fuzzy Color Image Segmentation ::Matlab

I'm working on a color image segmentation in HSV color space using Matlab fuzzy toolbox.
the goal is to read an RGB image->convert to hsv->use H,S,V values as an input for fuzzy system and then find which class(here is our 16 constant output color) does this pixel belongs.
here is the fuzzy system :
"The reasoning procedure is based on a zero-order Takagi-Sugeno model, so that the consequent part of each fuzzy rule is a crisp discrete value of the set{Black, White, Red, Orange,etc}.
Since this model has 10 fuzzy sets for Hue, 5 for Saturation and 4 for Value, the total number of rules required for this model is 10*5*4=200".(1)
The problem is that when I use this line in my program to get output value
segimg=reshape(evalfis([h s v],hsvRuleSugeno),imgh,imgw);
the out put is not any of my constant classes, because it uses centroid for defuzzification and as you see below I can't rely on it, as an output !
I search many papers and websites but I think it's so simple that no one explained it! I'm missing something or probably i don't have enough knowledge would you please help me to understand this problem ?
reference:
(1): Human Perception-based Color Segmentation Using Fuzzy Logic,Lior Shamir Department of Computer Science, Michigan Tech.
The paper explains the computation process in section 2.3. You do not need non-discrete or centroid value as obtained from evalfis. I'm assuming you have made all the rules which must be giving one of the 16 classes as output. That means each each output class is associated with at least one rule. According to the paper, you need to:
Make 16 groups containing rules associated to each output class. One group for yellow, one for white and one for black so on...
Calculate the strength of each and every rule.
For each group, find summation of strength value of all the rules contained in that group.
Then find the group with maximum cumulative sum of strength of its contained rules.
To achieve this, we cannot rely on centroid based defuzzified value. I checked the documentation on evalfis and below is script that should be able to perform above algorithm. Idea is to collect strength of each rule, order the rules into groups based on rule's output class, then find summation of each group and find maximum.
[output, IRR, ORR, ARR] = evalfis(input, fismat)
m = cat(2, ORR, ARR);
m = sortrows(m, 1)
r = [];
for l = 2 : size(m, 1)
if m(l, 1) ~= m(l - 1, 1)
r = cat(1, r, m(l - 1, :));
else
m(l, 2) = m(l, 2) + m(l - 1, 2);
end
end
if size(m, 1) >= 2
r = cat(1, r, m(size(m, 1), :));
end
% r now contains the final class to be choosen
disp(r)
Thanks a lot for your answer Shivam,
Actually your code has an error but I got the idea and started working on it, and finally found what to do ! here is what I use and the result was OK ! now I have to work on adjusting rules to get better results
for i=1:imh
for j=1:imw
[output, IRR, ORR, ARR] = evalfis([h(i,j);s(i,j);v(i,j)], hsvRuleSugeno);
m = cat(2,ARR,ORR);
[trash,idx] = unique(m(:,1),'first');
out = m(sort(idx),:);
out(:,[1,2])=out(:,[2,1]);
out = sortrows(out, 1);
res=zeros(size(out));
for l = 2 : size(out, 1)
if out(l, 1) == out(l - 1, 1)
res(l-1,1) = out(l-1,1);
res(l-1,2) = out(l-1,2)+out(l,2);
else
res(l,1) = out(l,1);
res(l,2) = out(l,2);
end
end
[num idx] = max(res(:,2));
[x y] = ind2sub(size(res),idx);
segimg(i,j)=res(x,y)/10;
end
end
the segment result :http://i45.tinypic.com/2aj9mg.jpg

Add the difference of two images in MATLAB

I am working on image processing. I want to add the difference of pixels of two images.
Suppose I have two images A, and B. I pick the first pixel of both images and store the difference value. I want to add this difference value to next pixel-difference. I try using this code, but it is not working. How can I do it?
A = imread('sub2.jpg');
B = imread('sub1.jpg');
tic
[rows cols] = size(A);
diff1 = 0;
for x = 1:rows
for y = 1:cols
diff = A(x,y)-B(x,y);
diff1 = diff1+diff;
end
end
disp(diff1);
toc
You can do it in one line as follows:
sum(sum(imsubtract(A-B)))
imsubtract subtracts two images and saves the difference in a matrix with the same size as A. Then, sum takes the sum of the result.
If you need absolute differences, you may use imabsdiff instead of imsubtract.
Note that the values of the differences are in 0 and 255. If you want negative instances, then you should directly subtract the matrices as A-B.
Looks okay though, but you're better off with:
diff1 = sum(sum(A-B));
or if B is larger than A:
diff1 = sum(sum(A-B(1:size(A,1),1:size(A,2))));
This gives just one value (as your code does), I'm not sure if that really is what you want..

Resources