MATLAB: Losing points near singularities? - matlab

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.

Related

Matlab Image Blob Detection Using Recursive Flood Fill

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.

Finding smallest value for parameterised answer that satisfies condition

I want to find the smallest integer l that satisfies l^2 >= x, and mod(l,2)=0.
In the following example x=75, and hence l=10, since the previous even number doesn't fulfil the inequation: 8^2 <= 75 <= 10^2
I have tried this (ignoring the even-number requirement, which I can't to work):
syms l integer
eqn1 = l^2 >= 75;
% eqn2 = mod(l,2) == 0;
[sol_l, param, cond] = solve(eqn1, l, 'ReturnConditions', true);
But this does not give me anything helpful directly:
sol_l =
k
param =
k
cond =
(75^(1/2) <= k | k <= -75^(1/2)) & in(k, 'integer')
I would like to evaluate the conditions on the parameter and find the smallest value that satisfies the conditions.
Also, I would like to enforce the mod(l,2)=0 condition somehow, but I don't seem to get that work.
Using the solve for this task is like using a cannon to kill a mosquito. Actually, the answer of Lidia Parrilla is good and fast, although it can be simplified as follows:
l = ceil(sqrt(x));
if (mod(x,2) ~= 0)
l = l + 1;
end
% if x = 75, then l = 10
But I would like to point out something that no one else noticed. The condition provided by the solve function for l^2 >= 75 is:
75^(1/2) <= k | k <= -75^(1/2)
and it's absolutely correct. Since l is being raised to the power of 2, and since a negative number raised to the power of 2 produces a positive number, the equation will always have two distinct solutions: a negative one and a positive one.
For x = 75, the solutions will be l = 10 and l = -10. So, if you want to find the smallest number (and a negative number is always smaller than a positive one), the right solution will be:
l = ceil(sqrt(x));
if (mod(x,2) ~= 0)
l = l + 1;
end
l = l * -1;
If you want to return both solutions, the result will be:
l_pos = ceil(sqrt(x));
if (mod(x,2) ~= 0)
l_pos = l_pos + 1;
end
l_neg = l_pos * -1;
l = [l_neg l_pos];
I guess the easiest solution without employing the inequality and solve function would be to find the exact solution to your equation l^2 >= x, and then finding the next even integer. The code would look like this:
x = 75;
y = ceil(sqrt(x)); %Ceil finds the next bigger integer
if(~mod(y,2)) %If it's even, we got the solution
sol = y;
else %If not, get the next integer
sol = y+1;
end
The previous code gives the correct solution to the provided example (x = 75; sol = 10)

Multi valued function graph in matlab

This is my first script in matlab. ( I cannot use functions)
Let's say I have a vector of time instants
t = [0:999]*1e-5; %vector of time instants
And my function is m
This is the part where it is implemented:
if (t >= 0)
if t <= to/3
m = 1;
elseif (t <= 2*to/3)
m = -2;
end
else
m = 0;
end
As I realised, m has only one value equal to 1.
How is this possible to have a 1x1000 value here? Where for values of t from 0 to to/3 -> m = 1, to/3 to 2*to/3 -> m = -2and else m=0
You can apply a function on each element of an array using arrayfun like the following:
arrayfun(#(x) m(x), t)
%or
arrayfun(#m, t)
You can find the details here. Also, you can implement your function like the following:
function result = m(t)
result = t;
result(t >= 0 && t <= to/3) = 1;
result(t > to/3 && t <= 2*to/3) = -2;
result(t < 0) = 0;
then call the function m on t such as m(t).

forcing the columns of a matrix within different limits

I have a matrix named l having size 20X3.
What I wanted to do was this :
Suppose I have this limits:
l1_max=20; l1_min=0.5;
l2_max=20; l2_min=0.5;
mu_max=20; mu_min=0.5;
I wanted to force all the elements of the matrix l within the limits.
The values of 1st column within l1_max & l1_min.
The values of 2nd column within l2_max & l2_min.
The values of 3rd column within mu_max & mu_min.
What I did was like this:
for k=1:20
if l(k,1)>l1_max
l(k,1) = l1_max;
elseif l(k,1)<l1_min
l(k,1) = l1_min;
end
if l(k,2)>l2_max
l(k,2) = l2_max;
elseif l(k,2)<l2_min
l(k,2) = l2_min;
end
if l(k,3)>mu_max
l(k,3) = mu_max;
elseif l(k,3)<mu_min
l(k,3) = mu_min;
end
end
Can it be done in a better way ?
You don't have to loop over rows, use vectorized operations on entire columns:
l(l(:, 1) > l1_max, 1) = l1_max;
l(l(:, 1) < l1_min, 1) = l1_min;
Similarily:
l(l(:, 2) > l2_max, 2) = l2_max;
l(l(:, 2) < l2_min, 2) = l2_min;
l(l(:, 3) > l2_max, 3) = mu_max;
l(l(:, 3) < l2_min, 3) = mu_min;
An alternative method, which resembles to Bas' idea, is to apply min and max as follows:
l(:, 1) = max(min(l(:, 1), l1_max), l1_min);
l(:, 2) = max(min(l(:, 2), l2_max), l2_min);
l(:, 3) = max(min(l(:, 3), mu_max), mu_min);
It appears that both approaches have comparable performance.
You don't even have to loop over all columns, the operation on the whole matrix can be done in 2 calls to bsxfun, independent of the number of columns:
column_max = [l1_max, l2_max, mu_max];
column_min = [l1_min, l2_min, mu_min];
M = bsxfun(#min, M, column_max); %clip to maximum
M = bsxfun(#max, M, column_min); %clip to minimum
This uses two tricks: to clip a value between min_val and max_val, you can do clipped_x = min(max(x, min_val), max_val). The other trick is to use the somewhat obscure bsxfun, which applies a function after doing singleton expansion. When you use it on two matrices, it 'extrudes' the smallest one to the same size as the largest one before applying the function, so the example above is equivalent to M = min(M, repmat(column_max, size(M, 1), 1)), but hopefully calculated in a more efficient way.
Below is a benchmark to test the various methods discussed so far. I'm using the TIMEIT function found on the File Exchange.
function [t,v] = testClampColumns()
% data and limits ranges for each column
r = 10000; c = 500;
M = randn(r,c);
mn = -1.1 * ones(1,c);
mx = +1.1 * ones(1,c);
% functions
f = { ...
#() clamp1(M,mn,mx) ;
#() clamp2(M,mn,mx) ;
#() clamp3(M,mn,mx) ;
#() clamp4(M,mn,mx) ;
#() clamp5(M,mn,mx) ;
};
% timeit and check results
t = cellfun(#timeit, f, 'UniformOutput',true);
v = cellfun(#feval, f, 'UniformOutput',false);
assert(isequal(v{:}))
end
Given the following implementations:
1) loop over all values and compare against min/max
function M = clamp1(M, mn, mx)
for j=1:size(M,2)
for i=1:size(M,1)
if M(i,j) > mx(j)
M(i,j) = mx(j);
elseif M(i,j) < mn(j)
M(i,j) = mn(j);
end
end
end
end
2) compare each column against min/max
function M = clamp2(M, mn, mx)
for j=1:size(M,2)
M(M(:,j) < mn(j), j) = mn(j);
M(M(:,j) > mx(j), j) = mx(j);
end
end
3) truncate each columns to limits
function M = clamp3(M, mn, mx)
for j=1:size(M,2)
M(:,j) = min(max(M(:,j), mn(j)), mx(j));
end
end
4) vectorized version of truncation in (3)
function M = clamp4(M, mn, mx)
M = bsxfun(#min, bsxfun(#max, M, mn), mx);
end
5) absolute value comparison: -a < x < a <==> |x| < a
(Note: this is not applicable to your case, since it requires a symmetric limits range. I only included this for completeness. Besides it turns out to be the slowest method.)
function M = clamp5(M, mn, mx)
assert(isequal(-mn,mx), 'Only works when -mn==mx')
idx = bsxfun(#gt, abs(M), mx);
v = bsxfun(#times, sign(M), mx);
M(idx) = v(idx);
end
The timing I get on my machine with an input matrix of size 10000x500:
>> t = testClampColumns
t =
0.2424
0.1267
0.0569
0.0409
0.2868
I would say that all the above methods are acceptably fast enough, with the bsxfun solution being the fastest :)

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.