Matlab Image Blob Detection Using Recursive Flood Fill - matlab

I am trying to do blob detection in Matlab. How can I get rid of my infinite recursion in flood_fill().
%Input Image
blobs = im2bw(imread('Week6Image.jpg'),0.1);
disp(blobs);
[W, H] = size(blobs);
region_labeling(blobs,W,H)
function region_labeling(I,W,H)
label = 2;
for u = 1 : W
%For loop vertical Axis
for v = 1 : H
if I(u,v) == 1
flood_fill(I,u,v,label,W,H);
label = label + 1;
end
end
end
end
It gets stuck in this function due to infinite recursion. What should I do so that it breaks out at the right time.
function flood_fill(I,u,v,label,W,H)
if u >= 1 && u < W && v >= 1 && v < H && I(u,v) == 1
I(u,v) = label;
flood_fill(I,u+1,v,label,W,H);
flood_fill(I,u,v+1,label,W,H);
flood_fill(I,u,v-1,label,W,H);
flood_fill(I,u-1,v,label,W,H);
end
end

I see the problem now: you are passing I into the function, but not getting the modifications back. MATLAB passes all arguments by value (with the exception of handle classes). This means that a function can change its input arguments without changing the value of those matrices in the caller's workspace. You need to modify the flood_fill function to return I.
The other issue is that blobs is a logical array, and assigning any non-zero value to it yields a value of 1. You need to cast it to some other type, either doubles with +blobs or a specific integer type as below.
This is the corrected code:
blobs = im2bw(imread('Week6Image.jpg'),0.1);
blobs = uint16(blobs); % or uint32 if you have many regions
[W, H] = size(blobs);
out = region_labeling(blobs,W,H);
function I = region_labeling(I,W,H)
label = 2;
for u = 1 : W
%For loop vertical Axis
for v = 1 : H
if I(u,v) == 1
I = flood_fill(I,u,v,label,W,H);
label = label + 1;
end
end
end
end
function I = flood_fill(I,u,v,label,W,H)
if u >= 1 && u <= W && v >= 1 && v <= H && I(u,v) == 1
I(u,v) = label;
I = flood_fill(I,u+1,v,label,W,H);
I = flood_fill(I,u,v+1,label,W,H);
I = flood_fill(I,u,v-1,label,W,H);
I = flood_fill(I,u-1,v,label,W,H);
end
end
Note also that it is beneficial, in a double loop, to have the fastest-changing index be the inner loop. MATLAB is column-major, so in I(u,v), u is the fastest-changing index. Thus, ideally you would swap the two for loops around. But, given that this is such a slow algorithm and that MATLAB is not so efficient with recursion, you will likely not see the difference in this particular piece of code.

Related

Double loop for each column per row in matlab

The following code does what it should and works of one column.
%% Working loop
z = HongKongPrices(1:end,114);
zeros = false(size(z));
r = size(z,1);
c = size(z,2);
for i = 5:r
if z(i) == z(i-4) && z(i) == z(i-3)
zeros(i-3:i) = 1
end
end
z(zeros) = NaN
I am trying to execute the for-loop on a per column basis for HongKongPrices, however the following code fails (I am starting with three columns for time reasons).
%% Non workling loop
z = HongKongPrices(1:end,[80 85 115]);
zeros = false(size(z));
r = size(z,1);
c = size(z,2);
for k = 1:c
x = z(1:end,k)
for i = 5:r
if x(i) == x(i-4) && x(i) == x(i-3)
zeros(i-3:i) = 1
end
end
end
x(zeros) = NaN
You don't need the variable x at all. You can use logical indexing in you if statement. Instead of x(i), use x(i,k) and so on. Of course you have to do the same with zeros.
z = HongKongPrices(1:end,[80 85 115]);
zeros = false(size(z));
r = size(z,1);
c = size(z,2);
for k = 1:c
for i = 5:r
if z(i,k) == z(i-4,k) && z(i,k) == z(i-3,k);
zeros(i-3:i,k) = 1
end
end
end
z(zeros) = NaN;
PS: zeros is a Matlab function, so it would be better to use another variable name. Like this you won't be able to use the zeros function in your code.

Plotting a loop in MATLAB

I am very new to MATLAB and am struggling to plot my data. In the program below I have modelled a relation between water level (m.a.s.l) and volume of water captured in a tank. Now I need to plot it in a way that H (water level) be in the Y-axis and V (Volume of the water) be in x-axis. However I have read a lot and tried a lot but still couldn't figure it out. Can Someone Help me PLS ??
I have tried to use simple Plot (X,Y) but it gives error. And so many other suggestions. I also tried fprintf function to have it a s a table in txt then plot it on Excel but always printed the last two H and V. not all of them.
for H = 410.03:0.01:414.57
L = 30; v = 0; fun1 = #(x) (0.3.^2-x.^2).^0.5;
if (H<410.03)
%For the heights below the tank, section 0
dis('No Water in the tank')
elseif (H>=410.03 && H<=410.33)
%section (1)
h = .3-(H-410.03) ;
a = (0.3.^2-h.^2).^0.5 ;
A = 2*(integral(fun1,0,a)-h*a);
V = A*L ;
disp(['H= ' num2str(H)])
disp(['V= ' num2str(V)])
elseif (H>410.33 && H<=410.38)
% section (1+2)
h = H-410.33 ;
V1 = L*(2*(integral(fun1,0,0.3)-0));
V = V1+(.6*h+22*h.^2)*L ;
disp(['H= ' num2str(H)])
disp(['V= ' num2str(V)])
elseif (H>410.38 && H<=414.57)
h = H - 410.38;
V1 = L*(2*(integral(fun1,0,0.3)-0));
V2 = V1+(0.085)*L;
V = V2 + (2.8*h)* L ;
disp(['H= ' num2str(H)])
disp(['V= ' num2str(V)])
end
end
This might get you started, although what I did here might not be the easiest first step to understand. I made a function H->V out of your code that can take a vector of values H and returns a vector V, suitable for plotting. If you want, you could make a simpler function that looks more like your original (with if-then-else structure) and takes a scalar H and returns a scalar V. Then you could loop over the range of H, creating V step-by-step.
First save a function like this (call the file somefunc.m):
function V = somefunc(H)
% constants
L = 30;
fun1 = #(x) (0.3.^2-x.^2).^0.5;
% set up return value (vector)
V = zeros(size(H));
% Section 1 (pick out the parts of H where it's within the first range)
section1 = find(H>=410.03 & H<=410.33);
h = .3-(H-410.03);
a = (0.3.^2-h.^2).^0.5 ;
% Have to loop here because integral won't take a vector of bounds
for i = section1
A(i) = 2*(integral(fun1,0,a(i))-h(i)*a(i));
end
V(section1) = A(section1)*L ;
% Section 1+2
section_1plus2 = find(H>410.33 & H<=410.38);
h = H-410.33 ;
V1 = L*(2*(integral(fun1,0,0.3)-0)); % scalar
V(section_1plus2) = V1+(.6*h(section_1plus2)+22*h(section_1plus2).^2)*L ;
% Section 3
section3 = find(H>410.38 & H<=414.57);
h = H - 410.38;
V1 = L*(2*(integral(fun1,0,0.3)-0)); % scalar
V2 = V1+(0.085)*L; % scalar
V(section3) = V2 + (2.8*h(section3))* L ;
Then you can run it like this:
H = 410.03 : 0.01 : 414.57;
V = somefunc(H);
plot(H,V);
xlabel('H')
ylabel('V')
I'd avoid having similarly named variables, especially the ones that are distinguished just by upper/lowercase.

How to Create Autocorrelation Function without any buit-in functions like xcorr

I want to auto-correlate a random noise vector with out any built-in MATLAB functions.
My auto correlation equation that is given is:
Rxx[L] = ∑ from n = 1 to N-1 [x(n)*x(n+L)]
L = [0:200]
I have written the code below but the plot Rxx vs L plot is not what I am expecting.
I am expecting my plot to start at some maximum at L = 0 or L = 1 since MATLAB starts its index at 1. Then exponentially decrease and saturates at a min of zero.
clc
clear all
randn('seed',2496132);
n = randn(1,1024);
upperbound = numel(n)-1;
for L = 1:200
for j = 1 : upperbound
n1(j) = n(j)+L;
Rxx(j) = (n(j)*n1(j));
end
Rxx_sum(L) = sum(Rxx);
Rxx = 0;
end
plot([1:200], Rxx_sum)
You have error in inner loop: you need to use n1(j) = n(j+L); instead n1(j) = n(j)+L;. E.g. you need add L to index instead value.
Second error is following: if you want to use upperbound = numel(n)-1 than you should use L equal to 0 or 1 only. E.g. you outer loop will be
for L = 0:1
...
Rxx_sum(L+1) = sum(Rxx);
...
Instead of this you can also correct upperbound value:
upperbound = numel(n) - maxL;
There maxL is maximal value of L that will used in next loop.
One more tip: it is possible to increase calculation speed if you replace inner loop with scalar product, e.g.
for L = 1:200
Rxx_sum(L) = n(1:upperbound) * n(1+L:upperbound+L)';
end
I ended up fixing my script with the help of the above code.
clc
clear all
randn('seed',2496132);
z = randn(1,1024);
n = [z zeros(1,200)];
upperbound = numel(z)-1;
for L = 0:200
for j = 1 : upperbound
Rxx(j) = (n(j)*n(j+L));
>end
Rxx_sum(L+1) = sum(Rxx);
Rxx = 0;
end
plot([0:200],Rxx_sum)

MATLAB: Losing points near singularities?

I am trying to plot some bump function supported on the interval (0,3). I've defined the function piecewise so that it is zero outside the interval. Here is the function:
function d = bump2(t)
region1 = (t > 0) & (t < 3);
d(region1) = exp(1./(t(region1).^2 - 3*t(region1)));
region2 = (t <= 0) & (t >= 3);
d(region2) = 0;
end
If I set x = -1:.01:4 and try to run plot(x,bump2(x)) I get an error telling me that my vectors aren't the same length. This is indeed true since length(x) = 501 and length(bump2(x)) = 400 However, when I set x = .01:.01:2.99, then everything checks out fine and the lengths of the vectors are equal.
Also, strangely, I have another, similar function
function b = bump(t)
region1 = abs(t) < 1;
b(region1) = exp(-1./(1 - ((t(region1)).^2)));
region2 = abs(t) >= 1;
b(region2) = 0;
end
with which I've never had this problem. Why are these two functions different? And why does the first function work when I exclude the points 0 and 3, even though I've defined the function to avoid possible singularities there?
This is because the b(region1) is trimming off the ends of your vector x so that it is not the same size.
Consider if you set x = -1:3 and then run the code plot(x, bump3(x)); with:
function d = bump3 (t)
region1 = (t > 0) & (t < 3);
d(region1) = t(region1);
end
Then you get the same problem. The issue is that inside bump3 you have
K>> region1
region1 =
0 0 1 1 0
Now this is the trick. This region1 is of data type logical so MATLAB interprets the next line
d(region1) = t(region1);
as
d(find(region1)) = t(find(region1));
But if you wrote
d = [];
d(5) = 1;
Then you would get a bunch of zeros at the zero, so you do here.
You might consider modifying to say d = t(region1); to get only the good values, but then you still have a sizing problem. A solution is to return the indices you used with the new value as an additional return value in bump like this:
Execute:
x = -1:3;
[y region1] = bump4(x);
plot(x(region1), y);
Where you modify your bump function like this:
function [d region1] = bump4 (t)
region1 = (t > 0) & (t < 3);
d = t(region1);
end
EDIT:
If you really do want those extra zeros on the left and right you can also fix this problem by initializing d before using it in your code like this:
function d = bump2(t)
region1 = (t > 0) & (t < 3);
d = zeros(size(t));
d(region1) = exp(1./(t(region1).^2 - 3*t(region1)));
region2 = (t <= 0) & (t >= 3);
d(region2) = 0;
end
Because I set d = zeros(...) then you have zeros outside the region and your bump function within it. Another way of looking at the problem is that MATLAB is padding on the left side but not on the right because you never set a blank value out there. This fixes that problem by telling MATLAB how big d should be.

Counting Number of Specific Outputs of a Function

If I have a matrix and I want to apply a function to each row of the matrix. This function has three possible outputs, either x = 0, x = 1, or x > 0. There's a couple things I'm running into trouble with...
1) The cases that output x = 1 or x > 0 are different and I'm not sure how to differentiate between the two when writing my script.
2) My function isn't counting correctly? I think this might be a problem with how I have my loop set up?
This is what I've come up with. Logically, I feel like this should work (except for the hiccup w/ the first problem I've stated)
[m n] = size(matrix);
a = 0; b = 0; c = 0;
for i = 1 : m
x(i) = function(matrix(m,:));
if x > 0
a = a + 1;
end
if x == 0
b = b + 1;
end
if x == 1
c = c + 1;
end
end
First you probably have an error in line 4. It probably should be i instead of m.
x(i) = function(matrix(i,:));
You can calculate a, b and c out of the loop:
a = sum(x>0);
b = sum(x==0);
c = sum(x==1);
If you want to distinguish x==1 and x>0 then may be with sum(xor(x==1,x>0)).
Also you may have problem with precision error when comparing double values with 0 and 1.