A way to reduce run-time - matlab

I have a 2048x2048 image and I want to re-set the pixels values according to certain condition. The problem is that it takes houres (if not days) for the code to end. Is there a way to shorten the run-time?
This is the function:
function ProcImage = ProcessImage(X,length,width)
for i=1:length
for j=1:width
if X(j,i)<=0.025*(max(max(X(:,:))))
X(j,i)=0;
else
if X(j,i)>=0.95*(max(max(X(:,:))))
X(j,i)=(max(max(X(:,:))));
end
end
end
end
ProcImage=X(1:end,1:end);
thanks in advance.

Vectorize it. You don't need to compute the maximum value of X on every iteration, since it will be the same throughout. Compute it once, store that value, then use it later. You can also do away with the loops by using element-wise logical operations and matrix indexing. Here's a simplified version that should be much faster:
maxX = max(X(:));
X(X <= 0.025.*maxX) = 0;
X(X >= 0.95.*maxX) = maxX;

If your image is a gray scale image that its values are in the range 0 to 255 here is a possible solution:
m = max(X(:));
tbl = 0:255;
tbl(tbl<=0.025*m)=0;
tbl(tbl>=0.95*m)=m;
X = tbl(int16(X)+1);

Related

Matlab: deciding whether a value is between the column entries of a nx2 matrix

I am writing a Matlab Tool and certain processes have to be automated.
I am running a for loop, in which some decisions need to be made. Here is a piece of my code:
DecisionMatrix = [0.2 0.4; 0.5 0.7];
Beta =0:pi/20:pi;
Span_Loc = 0.5*(1-cos(Beta))';
for i=1:length(Span_Loc)
Position = Span(i)
% Check Clean of High Lift
if Position >= DecisionMatrix(1,1) && Position <= DecisionMatrix(1,2)
% HighLift run code here
elseif Position >= DecisionMatrix(2,1) && Position <= DecisionMatrix(2,2)
else
% Clean run code here
end
end
Herein, DecisionMatrix is a variable size matrix which is nx2 always. What I want to do is to determine when the value of Position is between the entries of any row of DecisionMatrix. This should be easy when DecisionMatrix is a constant matrix (as shown above). However, this matrix has a variable number of rows.
Hence, how would you do this?
Thanks in advance!!
To determine when the value of Position (scalar) is between the entries of any row of DecisionMatrix (2-column matrix):
result = any(Position>=DecisionMatrix(:,1) & Position<=DecisionMatrix(:,2));
The above gives a logical result (true or false). If you need to know the indices of the rows that fulfill the condition:
result = find(Position>=DecisionMatrix(:,1) & Position<=DecisionMatrix(:,2));
You can fix your code by introducing another loop and coming out of it when you find the required row.
DecisionMatrix = [0.2 0.4; 0.5 0.7];
Beta =0:pi/20:pi;
Span_Loc = 0.5*(1-cos(Beta))';
for p=1:length(Span_Loc)
Position = Span(p);
for q=1:n
if Position >= DecisionMatrix(q,1) && Position <= DecisionMatrix(q,2)
%do what you want when the condition is true
break
end
end
end

Loop through data set until specific point - Matlab

I've run an experiment where a machine exerts a force on a bridge until it breaks. I need to cycle through my entire data set and calculate the toughness until I've hit the breaking point (fdValue1).
The toughness is calculated by summing up all the rectangles under my load vs. distance curve. (Basically the integral)
However, I have not been able to find a reasonable way of doing so and my current loop is an infinite loop and I'm not sure why.
%Initializing variables
bridge1Data = xlsread('Bridge1Data.xlsx', 'A2:C2971');
bridge2Data = xlsread('Bridge2Data.xlsx', 'A2:C1440');
bridge1Load = bridge1Data(:, 2);
bridge2Load = bridge2Data(:, 2);
bridge1Dist = bridge1Data(:, 3);
bridge2Dist = bridge2Data(:, 3);
[row1, col1] = size(bridge1Dist);
[row2, col2] = size(bridge2Dist);
bridge1Disp = zeros(row1, col1);
bridge2Disp = zeros(row2, col2);
fdValue1 = 0.000407350000000029;
&Main code
%Displacement
for k = 2:length(bridge1Dist)
bridge1Disp(k-1, 1) = bridge1Dist(k, 1) - bridge1Dist(k-1, 1);
end
%Max Load Bridge 1
maxLoad1 = 0;
for n = 1:length(bridge1Load)
for k = 1
if bridge1Load(n, k) > maxLoad1
maxLoad1 = bridge1Load(n, k);
end
end
end
%Cycle through data till failure, change proj data
totalRect1 = 0;
for j = 2:length(bridge1Disp)
while bridge1Disp(j, 1) ~= fdValue1
rectangle = (bridge1Disp(j, 1) - bridge1Disp(j-1, 1))*...
((bridge1Load(j, 1) + bridge1Load(j-1, 1))/2);
totalRect1 = totalRect1 + rectangle;
end
end
Basically, I make an array for the load and distance the machine pushes down on the bridge, assign a 'Failure Distance' value (fdValue) which should be used to determine when we stop calculating toughness. I then calculate displacement, calculate the maximum load. Then through the variable 'rectangle', calculate each rectangle and sum them all up in 'totalRect1', and use that to calculate the toughness by finding the area under the curve. Is anyone able to see why the loop is an infinite loop?
Thanks
The problem with the condition while bridge1Disp(j, 1) ~= fdValue1 is that you need to check for <= and not for (in)equality, since double numbers will almost never evaluate to be equal even if they seem so. To read more about this you can look here and also google for matlab double comparison. Generally it has something to do with precision issues.
Usually when checking for double equality you should use something like if abs(val-TARGET)<1E-4, and specify some tolerance which you are willing to permit.
Regardless,
You don't need to use loops for what you're trying to do. I'm guessing this comes from some C-programming habits, which are not required in MATLAB.
The 1st loop (Displacement), which computes the difference between every two adjacent elements can be replaced by the function diff like so:
bridge1Disp = diff(bridge1Dist);
The 2nd loop construct (Max Load Bridge 1), which retrieves the maximum element of bridge1Load can be replaced by the command max as follows:
maxLoad1 = max(bridge1Load);
For the last loop construct (Cycle ...) consider the functions I've mentioned above, and also find.
In the code section
%Cycle through data till failure, change proj data
totalRect1 = 0;
for j = 2:length(bridge1Disp)
while bridge1Disp(j, 1) ~= fdValue1
rectangle = (bridge1Disp(j, 1) - bridge1Disp(j-1, 1))*...
((bridge1Load(j, 1) + bridge1Load(j-1, 1))/2);
totalRect1 = totalRect1 + rectangle;
end
end
the test condition of the while loop is
bridge1Disp(j, 1) ~= fdValue1
nevertheless, in the while loop the value of bridge1Disp(j, 1) does not change so if at the first iteratiion of the while loop bridge1Disp(j, 1) is ~= fdValue1 the loop will never end.
Hope this helps.

Selecting objects overlapping a pixel in matlab

I'm implementing some sort of flood fill algorithm in Matlab that, given a starting pixel in a binary image, will output a binary image containing only the pixels that can be directly connected to it.
Basically, let
foo =
1 1 1
1 0 0
1 0 1
calling flood_fill(foo,1,1) would yield
1 1 1
1 0 0
1 0 0
Now, I'm pretty new to Matlab. I initially implemented flood_fill in a recursive style, but the pass-by-value behaviour of Matlab made working with large images very inefficient. To fix this, I reimplemented flood_fill like this
function [outImage] = flood_fill(inImage,start_x,start_y)
width = size(inImage,2);
height = size(inImage,1);
outImage = zeros(height,width);
points = [];
points = [points; [start_x start_y]];
while size(points,1)>0
point = points(1,:);
points = points(2:end,:);
y=point(2);
x=point(1);
outImage(y,x)=1;
if (y>1 && (outImage(y-1,x)==0) && (inImage(y-1,x)==1))
points = [points; [x y-1]];
end
if (y<height && (outImage(y+1,x)==0) && (inImage(y+1,x)==1))
points = [points; [x y+1]];
end
if (x>1 && (outImage(y,x-1)==0) && (inImage(y,x-1)==1))
points = [points; [x-1 y]];
end
if (x<width && (outImage(y,x+1)==0) && (inImage(y,x+1)==1))
points = [points; [x+1 y]];
end
end
end
Now, this works on small matrices/images but takes forever on large images as well. I suspect the reason why is the large amount of array resizes going on. Normally (in C++ for example), I'd use an unordered linked list and use it as a stack (remove from and insert at the head) to avoid costly array resizes.
Is there an equivalent to such a data structure in Matlab? If not, what's a Matlab idiom I could use? Perhaps a built-in function?
The function that you search for called bwselect:
foo=[1 1 1; 1 0 0; 1 0 1]
b=bwselect(foo,1, 1)
Note that you can define also fourth input n (like that: bwselect(foo,1,1,n)), that can have a value of 4 to specify 4-connected region, or 8 to specify 8-connected region.
Adiel answered your second question "Perhaps a built-in function?". As for the first part:
I'm not familiar with linked lists in MATLAB. However, you can speed up your function significantly by initializing the size of the points-matrix and don't change the size after that. Pre-initialization should always be done in MATLAB. If the function won't work with matrices of fixed size, I would always recommend you to try to rewrite the function.
For your specific case:
function [outImage] = flood_fill(inImage,start_x,start_y)
width = size(inImage,2);
height = size(inImage,1);
outImage = zeros(height,width);
points = zeros(nnz(inImage),2); % I take it this is the maximum size
points(1,:) = [start_x start_y];
k = 1; % Increment row number in points
while size(points,1)>0
k = k + 1;
y=points(k, 2);
x=points(k, 1);
I understand it you have programming skills in general, so I believe you should be able to adapt the remaining code to the new format. (I don't have time to go through it and rewrite it). I'm quite sure it will run much faster!

Is there any way to add perturbation to a variable in Matlab?

I have a 101x82 size matrix called A. I am trying to minimize an objective function obj_fun, whose value is computed indirectly using A.
Now in order to minimize this objective function obj_fun, I need to perturb the values of A. I want to check if obj_fun is going down in values or not. If not, then I need to do perturb/change values of A to a certain percentage such that it minimizes obj_fun. Keep on perturbing/changing values of A until we get minimum obj_fun. My average value of A before any perturbation is ~ 1.1529e+003.
Does any one have suggestion how can I do this? Also, I care a bit about speed i.e. the method/algorithm should not be too slow. Thanks.
You can add random Gaussian noise to A:
A = 0; % seed value for A with something more interesting than 0
best = obj_fun(A);
for iter = 1:max_iter % max_iter should be the maximum number of iterations
newA = A + normrnd(0, 1, size(A));
newObj = obj_fun(A);
if( newObj < best )
best = newObj;
A = newA;
end
end

Cutting down large matrix iteration time

I have some massive matrix computation to do in MATLAB. It's nothing complicated (see below). I'm having issues with making computation in MATLAB efficient. What I have below works but the time it takes simply isn't feasible because of the computation time.
for i = 1 : 100
for j = 1 : 20000
element = matrix{i}(j,1);
if element <= bigNum && element >= smallNum
count = count + 1;
end
end
end
Is there a way of making this faster? MATLAB is meant to be good at these problems so I would imagine so?
Thank you :).
count = 0
for i = 1:100
count = count + sum(matrix{i}(:,1) <= bigNum & matrix{i}(:,1) >= smallNum);
end
If your matrix is a matrix, then this will do:
count = sum(matrix(:) >= smallNum & matrix(:) <= bigNum);
If your matrix is really huge, use anyExceed. You can profile (check the running time) of both functions on matrix and decide.