Avoid restarting for-loop - matlab

I have a folder with pictures. For each picture, I want to take the maximum value and add it to a new matrix (I created a zeros-matrix, so the zeroes will be replaced with the new values).
This is my code:
function handles = original(hObject, eventdata, handles)
handles.weed=handles.selected;
pic=imread(handles.me);
handles.pic=pic;
axes(handles.axes1)
imshow(pic);
num=max(pic(:))
zeroMat = zeros(1,70);
handles.zeroMat = zeroMat;
for i =1:3
if zeroMat(1,i)~= 0;
i=i+1
else
zeroMat(1,i)=num
break
end
end
zeroMat(1,i)=num
Every time I select a new picture, the zeromat restarts itself to a new zeros-matrix. I know why it happens, but unfortunately I don't know how to overcome it.
This is the output:
pic1:
zeroMat =
Columns 1 through 20
255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 21 through 40
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 41 through 60
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 61 through 70
0 0 0 0 0 0 0 0 0 0
pic2:
Columns 1 through 20
203 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 21 through 40
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 41 through 60
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 61 through 70
0 0 0 0 0 0 0 0 0 0

I can't tell how this function is being invoked, so can't advice how to change up the logic. A rough fix could be to include the line
if ~isfield(handles,'zeroMat')
handles.zeroMat = zeros(1,70);
end % if
which should create handles.zeroMat the first time the function is run. You could then do something like
firstNonzero = find(handles.zeroMat > 0, 1, 'first'); % 'first' not needed, default
handles.zeroMat(firstNonzero) = max(pic(:));

Related

How to correctly use the col2im function?

This function is confusing to use, and it always gives me an error:
To RESHAPE the number of elements must not change.
That's my code:
im=im2col(zeros(300,300),[3 3]);
im(:,9)=ones(9,1);
im=col2im(im,[3 3],[300 300]);
Basically, this code just gets the block at index 6, replaces it with ones, and reassembles it back into the original image. What's wrong with this code?
It seems you want to create distinct blocks from your input array, change single blocks, and rearrange them. (Your target size is the same as your input array size.) So, you must use the distinct parameter in both, im2col as well as col2im:
blk_size = [3, 3];
im = zeros(9, 9)
temp = im2col(im, blk_size, 'distinct');
temp(:, 3) = ones(prod(blk_size), 1);
im2 = col2im(temp, [3 3], size(im), 'distinct')
Output:
im =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
im2 =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
When using im2col with the sliding parameter, which is also the default, if no parameter is set at all, there'll be a lot more columns in the result than can be rearranged to the input array size, cf. the Tips section on im2col.
Hope that helps!

Read from a file into a vector in matlab using importdata()

My input file looks like this:
# FILE:app/src/f1.c
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 32 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
# FILE:src/f2.c
1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 31 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
...............
I want to read the headers i.e., the lines which start with #, and the vectors present below the headers into lists. I tried the using importdata() as below. But this gives me only the first header and first vector. I need to read it till the end of the file.
filename = 'output.txt';
A = importdata(filename);
disp(A.rowheaders);
disp(A.data);
EDIT: A = importdata(filename,'#'); This solved my problem
I believe the fgetl command should do the trick.
I would put it in a for loop with two fgetl commands, one for the metadata line and one for the numerical data line.
EDIT: Added example
fid = fopen('test.txt');
celHeaders = {};
celData = {};
while(~feof(fid))
celHeaders{end+1} = fgetl(fid);
celData{end+1} = fgetl(fid);
end
fclose(fid);
disp(celHeaders)
disp(celData)
This is assuming that your text file doesn't include additional lines above or below the data.

Matlab: keeping non-zero matrix elements adjacent to each other and ignoring lone elements

Here is an example matrix (but the result shouldn't be constrained to only working on this):
a=zeros(7,7);
a(5,3:6)=1;
a(2,2)=1;
a(2,4)=1;
a(7,1:2)=1
a=
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
1 1 0 0 0 0 0
I want to get rid of all the 1's that are alone (the noise), such that I only have the line of 1's on the fifth row.
rules:
-the 1's are in 'connected lines' if there are adjacent 1's (including diagonally) e.g.:
0 0 0 1 0 0 1 0 1
1 1 1 0 1 0 0 1 0
0 0 0 0 0 1 0 0 0
(The connected lines are what I want to keep. I want to get rid of all the 1's that are not in connected lines, the connected lines can intersect each other)
the 'connected lines need to be at least 3 elements long. So in the 7x7 example, there would only be one line that matches this criteria. If a(7,3) was set to 1, then there would be a connected line at the bottom left also
I am currently looking at this through a column by column approach, and here is the first draft of my code so far:
for nnn=2:6
rowPoss=find(a(:,nnn)==1);
rowPoss2=find(a(:,nnn+1)==1);
for nn=1:length(rowPoss)
if myResult(rowPoss(nn)-1:rowPoss(nn)+1,n-1)==0 %
%then?
end
end
end
My difficulty is, during this column by column process, I'd have to enable a way to recognise the beginning of the connected line, the middle of the connected line, and when a connected line ends. The same rules for this, when applied to noise (the lone 1's), would just ignore the lone 1's.
The output I want is basically:
b=
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
If you have image processing toolbox, try bwareaopen
b = bwareaopen(a, 3);
Sample Run #1:
>> a
a =
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
1 1 0 0 0 0 0
>> b
b =
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
Sample Run #2:
>> a
a =
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
1 1 0 0 0 0 0
>> b
b =
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0

"""Diagonal""" -1/+1 Matrix

I need to construct the tech cycle constraint matrix Aa and the right side ba. The aim is building the technology cycle matrices in order to solve the scheduling linear problem constrained by Ax<=b. In this case -1 and +1 in A refers to the coefficients of the constraints of the problem such as starting times and precedences
TC = [1,2,3,4,6,7;1,2,5,4,6,7;2,5,6,7,0,0]; % Technology cycle
CT = [100,60,200,160,80,120;100,60,150,120,60,150;50,120,40,30,0,0]; % Cycle time
n_jb = size(TC,1); % number of jobs
n_op = sum(TC~=0,2); % number of operations for each job
N_op = sum(n_op); % total number of operations
c=1; % indice for constraints in Aa
Op=1; % counter for overall operation
n_tf = N_op - n_jb- sum(n_op==1); % number of job transfer between machines (also number of tech cycle constraint numbers)
Aa = zeros(n_tf,N_op); % Constraint matrx for tech cycle
ba = zeros(n_tf,1); % The right vector of the constraint function: Aa*x<=ba
for j=1:n_jb
if n_op(j)>1
for op=1:n_op(j)-1
Aa(c,Op)=-1;
Aa(c,Op+1)=1;
ba(c,1)=CT(j,op);
c=c+1;
Op=Op+1;
end
else
Op=Op+1;
end
Op=Op+1;
end
The output, like Aa is 3 """diagonal""" -1/+1 matrices:
-1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1
In order to be more precise in the following there is an image: showing the 3 different part of the matrix Aa. My question is: Is there a way to build the same this avoiding loops since A is not a 3x1 but will definitely become 30-50x1?
You can use diag to create the positive and negative ones. The second input to diag is to shift the diagonal to the side. In this case, 1 to the right.
Use cumsum to find the rows you want to remove. For n = [6, 6, 4], you want to remove the 6th, 12th and 16th row.
n = [6, 6, 4];
cols = sum(n);
A = -eye(cols) + diag(ones(cols-1,1), 1);
A(cumsum(n),:) = []
A =
-1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1

Tallying co-incidences of numbers in columns of a matrix - MATLAB

I have a matrix (A) in the form of (much larger in reality):
205 204 201
202 208 202
How can I tally the co-incidence of numbers on a column-by-column basis and then output this to a matrix?
I'd want the final matrix to run from min(A):max(A) (or be able to specify a specific range) across the top and down the side and for it to tally co-incidences of numbers in each column. Using the above example:
200 201 202 203 204 205 206 207 208
200 0 0 0 0 0 0 0 0 0
201 0 0 1 0 0 0 0 0 0
202 0 0 0 0 0 1 0 0 0
203 0 0 0 0 0 0 0 0 0
204 0 0 0 0 0 0 0 0 1
205 0 0 0 0 0 0 0 0 0
206 0 0 0 0 0 0 0 0 0
207 0 0 0 0 0 0 0 0 0
208 0 0 0 0 0 0 0 0 0
(Matrix labels are not required)
Two important points: The tallying needs to be non-duplicating and occur in numerical order. For example a column containing:
205
202
Will tally this as a 202 occurring with 205 (as shown in the above matrix) but NOT 205 with 202 - the duplicate reciprocal. When deciding what number to use as the reference, it should be the smallest.
EDIT:
sparse to the rescue!
Let your data and desired range be defined as
A = [ 205 204 201
202 208 202 ]; %// data. Two-row matrix
limits = [200 208]; %// desired range. It needn't include all values of A
Then
lim1 = limits(1)-1;
s = limits(2)-lim1;
cols = all((A>=limits(1)) & (A<=limits(2)), 1);
B = sort(A(:,cols), 1, 'descend')-lim1;
R = full(sparse(B(2,:), B(1,:), 1, s, s));
gives
R =
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Alternatively, you can dispense with sort and use matrix addition followed by triu to obtain the same result (possibly faster):
lim1 = limits(1)-1;
s = limits(2)-lim1;
cols = all( (A>=limits(1)) & (A<=limits(2)) , 1);
R = full(sparse(A(2,cols)-lim1, A(1,cols)-lim1, 1, s, s));
R = triu(R + R.');
Both approaches handle repeated columns (up to sorting), correctly increasing their tally. For example,
A = [205 204 201
201 208 205]
gives
R =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
See if this is what you were after -
range1 = 200:208 %// Set the range
A = A(:,all(A>=min(range1)) & all(A<=max(range1))) %// select A with columns
%// that fall within range1
A_off = A-range1(1)+1 %// Get the offsetted indices from A
A_off_sort = sort(A_off,1) %// sort offset indices to satisfy "smallest" criteria
out = zeros(numel(range1)); %// storage for output matrix
idx = sub2ind(size(out),A_off_sort(1,:),A_off_sort(2,:)) %// get the indices to be set
unqidx = unique(idx)
out(unqidx) = histc(idx,unqidx) %// set coincidences
With
A = [205 204 201
201 208 205]
this gets -
out =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Few performance-oriented tricks could be used here -
I. Replace
out = zeros(numel(range1));
with
out(numel(range1),numel(range1)) = 0;
II. Replace
idx = sub2ind(size(out),A_off_sort(1,:),A_off_sort(2,:))
with
idx = (A_off_sort(2,:)-1)*numel(range1)+A_off_sort(1,:)
What about a solution using accumarray? I would first sort each column independently, then use the first row as first dimension into the final accumulation matrix, then the second row as the second dimension into the final accumulation matrix. Something like:
limits = 200:208;
A = A(:,all(A>=min(limits)) & all(A<=max(limits))); %// Borrowed from Divakar
%// Sort the columns individually and bring down to 1-indexing
B = sort(A, 1) - limits(1) + 1;
%// Create co-occurrence matrix
C = accumarray(B.', 1, [numel(limits) numel(limits)]);
With:
A = [205 204 201
202 208 202]
This is the output:
C =
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
With duplicates (borrowed from Luis Mendo):
A = [205 204 201
201 208 205]
Output:
C =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0