I have a matrix. The entries are all integers. For example, my matrix would look like this
M = 1 1 1 2 2 2 2 3 3
1 1 1 2 2 2 2 3 0
4 4 4 5 5 5 5 0 0
4 4 4 5 5 5 0 0 0
4 4 4 5 5 0 0 0 0
4 4 4 5 0 0 0 0 0
6 6 6 0 0 0 0 0 0
6 6 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0
I wonder if matlab has some neat function to plot the boundary of these sets generated by this matrix?
I think you are looking for a variation of contour plot. Don't forget that it will flip Y axis.
contour(M)
g = gca;
g.YDir = 'reverse';
for jj=1:size(M,1)
for ii=1:size(M,2)
text(jj,ii,num2str(M(ii,jj)));
end
end
Related
I have a vector ("d") which I want to place it's content to a matrix ("dis"), I have the problem to create "dis" matrix. "dis" should be like
dis=[
1 2 3 4 5 6 7 8 9 10 11 12
0 1 2 3 4 5 6 7 8 9 10 11
0 0 1 2 3 4 5 6 7 8 9 10
0 0 0 1 2 3 4 5 6 7 8 9
0 0 0 0 1 2 3 4 5 6 7 8
0 0 0 0 0 1 2 3 4 5 6 7
0 0 0 0 0 0 1 2 3 4 5 6
0 0 0 0 0 0 0 1 2 3 4 5
0 0 0 0 0 0 0 0 1 2 3 4
0 0 0 0 0 0 0 0 0 1 2 3
0 0 0 0 0 0 0 0 0 0 1 2
0 0 0 0 0 0 0 0 0 0 0 1];
n=[0,0;1,0;2,0;3,0;4,0;5,0;6,0;7,0;8,0;9,0;10,0;11,0;12,0];
d=pdist(n,'euclidean');
l=length(n)-1;
dis=[];
for k=1:length(n)-1
dis=[dis;d((k-1)*l-(k*((k-1)/2))+k):d(k*l-((k+1)*k/2)+k)];
end
The problem is that you are not padding dis with the zeros.
You can replace
dis=[];
for k=1:length(n)-1
dis=[dis;d((k-1)*l-(k*((k-1)/2))+k):d(k*l-((k+1)*k/2)+k)];
end
with
dis = zeros(l);
for k=1:l
dis(k,k:end) = d((k-1)*l-(k*((k-1)/2))+k):d(k*l-((k+1)*k/2)+k)
end
Using squareform form #beaker comment above, you can write:
dis = triu(squareform(d));
dis = dis(1:length(dis)-1,2:length(dis));
Does this solves the problem?
I want to find the non-intersecting rows in a large matrix. As an example:
A=[1 5 3; 3 4 5; 7 9 10;4 5 6;11 2 8; 3 5 10]
In this matrix, the non-intersecting rows are: [1 5 3], [11 2 8] and [7 9 10]. How can I program this in Matlab in a fast way?
If I may bsxfun -
M = squeeze(any(bsxfun(#eq,A,permute(unique(A),[3 2 1])),2))
[~,row_idx] = max(M,[],1)
out = A(sum(M,2).' == histc(row_idx,1:size(A,1)),:)
Sample step-by-step run -
A =
1 5 3
3 4 5
7 9 10
4 5 6
11 2 8
3 5 10
M =
1 0 1 0 1 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 0 1 1 0
0 0 0 1 1 1 0 0 0 0 0
0 1 0 0 0 0 0 1 0 0 1
0 0 1 0 1 0 0 0 0 1 0
row_idx =
1 5 1 2 1 4 3 5 3 3 5
out =
1 5 3
7 9 10
11 2 8
You can look for rows that adding them to union of previous rows increases the number of elements in the union by the number of columns (i.e. all elements in that row are new):
B = [];
C = zeros(1,size(A,1));
for k=1:size(A,1),
B1 = union(B, A(k,:));
C(k) = numel(B1)-numel(B);
B=B1;
end
result = A(C==size(A,2),:);
Let's say I have a square matrix M:
M = [0 0 0 0 0 1 9; 0 0 0 0 0 4 4; 0 0 1 1 6 1 1; 0 1 2 9 2 1 0; 2 1 8 3 2 0 0; 0 8 1 1 0 0 0; 14 2 0 1 0 0 0]
0 0 0 0 0 1 9
0 0 0 0 0 4 4
0 0 1 1 6 1 1
M = 0 1 2 9 2 1 0
2 1 8 3 2 0 0
0 8 1 1 0 0 0
14 2 0 1 0 0 0
Now I'd like to calculate two different cumulative sums: One that goes from the top of each column to the element of the column, that is a diagonal element of the matrix, and one that goes from the bottom of the column to the same diagonal element.
The resulting matrix M'should therefore be the following:
0 0 0 0 0 1 9
0 0 0 0 0 4 5
0 0 1 1 6 2 1
M' = 0 1 3 9 4 1 0
2 2 8 5 2 0 0
2 8 1 2 0 0 0
14 2 0 1 0 0 0
I hope the explanation of what I'm trying to achieve is comprehensible enough. Since my matrices are much larger than the one in this example, the calculation should be efficient as well...but so far I couldn't even figure out how to calculate it "inefficiently".
In one line using some flipping and the upper triangular function triu:
Mp = fliplr(triu(fliplr(cumsum(M)),1)) ...
+flipud(triu(cumsum(flipud(M)),1)) ...
+flipud(diag(diag(flipud(M))));
The following will do the job:
Mnew = fliplr(triu(cumsum(triu(fliplr(M)),1))) + flipud(triu(cumsum(triu(flipud(M)),1)));
Mnew = Mnew - fliplr(diag(diag(fliplr(Mnew)))) + fliplr(diag(diag(fliplr(M))));
But is it the fastest method?
I think logical indexing might get you there faster
I'm trying to copy part of a matrix (matrix 1) in matlab to another empty matrix of zeros (matrix 2) so that the section I copy from matrix 1 has the same indices in matrix 2, e.g.
Matrix 1 (mat1):
0 3 0 0 2 4 1 2 6
1 3 4 2 0 0 0 2 0
0 2 6 1 3 6 6 1 1
0 0 0 2 1 3 3 1 0
1 4 5 2 3 3 0 0 1
Matrix 2 (mat2) desired output:
0 0 0 0 0 0 0 0 0
0 0 4 2 0 0 0 0 0
0 0 6 1 3 6 6 0 0
0 0 0 2 1 3 3 0 0
0 0 0 0 0 0 0 0 0
I've tried something like
mat2([2:4],[3:7]) = mat1([2:4],[3:7])
but of course it doesn't work... any ideas of an efficient way to do this? I couldn't find another thread to help with this problem.
Thanks!
It does work. You just need to create mat2 first:
mat2 = zeros(size(mat1));
mat2(2:4, 3:7) = mat1(2:4, 3:7);
Note that you don't need the square brackets on those ranges.
Do this:
mat2 = zeros(size(mat1));
Before copying over.
I am working on Connected Components labeling, and my matrix is:
1 1 0 2 2 2 0 3
1 1 0 2 0 2 0 3
1 1 1 1 0 0 0 3
0 0 0 0 0 0 0 3
4 4 4 4 0 5 0 3
0 0 0 4 0 5 0 3
6 6 0 4 0 0 0 3
6 6 0 4 0 7 7 7
and now, i want to do the second scan over it, for this i have made following code:
for i=1:1:r
for j=1:1:c
if (bw(i,j)>=1)
if (i-1>0 & i+1<=r)
% if ( bw(i,j)~= bw(i-1,j) | bw(i,j)~= bw(i+1,j))
if ( (bw(i,j)~= bw(i-1,j) & bw(i-1,j)>0))
bw(i,j)= min (bw(i-1,j),bw(i,j))
elseif ((bw(i,j)~= bw(i+1,j) & bw(i+1,j)>0))
bw(i,j) = min(bw(i+1,j),bw(i,j));
end
end
if (j-1>0 & j+1<=c)
if ( (bw(i,j)~= bw(i,j-1) & bw(i,j-1)>0))
bw(i,j) = min (bw(i,j-1),bw(i,j));
elseif((bw(i,j)~= bw(i,j+1) & bw(i,j+1)>0))
bw(i,j) = min (bw(i,j+1),bw(i,j)) ;
end
end
end
end
end
disp(bw);
but the problem is, when i run this code, i get the following output
1 1 0 2 2 2 0 3
1 1 0 1 0 2 0 3
1 1 1 1 0 0 0 3
0 0 0 0 0 0 0 3
4 4 4 4 0 5 0 3
0 0 0 4 0 5 0 3
6 6 0 4 0 0 0 3
6 6 0 4 0 7 7 7
only one value changes (2nd row, 4 col) in my result, whereas, I want:
1 1 0 1 1 1 0 3
1 1 0 1 0 1 0 3
1 1 1 1 0 0 0 3
0 0 0 0 0 0 0 3
4 4 4 4 0 5 0 3
0 0 0 4 0 5 0 3
6 6 0 4 0 0 0 3
6 6 0 4 0 3 3 3
could somebody please help? where am i making a mistake?
Nice solution by Jonas. As I was a bit into coding when I saw it added, I thought I'd show you my solution as well. Hopefully it is a bit more similar to your original code.
One of the mistakes you made was assuming this connection could be done in just one pass. Generaly it can not, as detections of some of the "snake elements" are dependent on the way you iterate throught the matrix. Becuase of this, I added an outer while loop.
bw =[ 1 1 0 2 2 2 0 3;
1 1 0 2 0 2 0 3;
1 1 1 1 0 0 0 3;
0 0 0 0 0 0 0 3;
4 4 4 4 0 5 0 3;
0 0 0 4 0 5 0 3;
6 6 0 4 0 0 0 3;
6 6 0 4 0 7 7 7 ];
%Set up matrix
[r,c] = size(bw);
%Zero pad border
bwZ = [zeros(1,c+2);[zeros(r,1) bw zeros(r,1)];zeros(1,c+2)];
%Iterate over all elements within zero padded border
done=0;%Done flag
cc=1; %Infinite loop protection
while not(done) && cc<r*c
done=1;cc=cc+1;
for i=2:r+1
for j=2:c+1
%Point should be evaluated
p = bwZ(i,j);
if p >= 1
%Pick out elements around active elements
if bwZ(i-1,j)==0;ue=inf;else ue = bwZ(i-1,j); end;%Up element
if bwZ(i+1,j)==0;de=inf;else de = bwZ(i+1,j); end;%Down element
if bwZ(i,j-1)==0;le=inf;else le = bwZ(i,j-1); end;%Left element
if bwZ(i,j+1)==0;re=inf;else re = bwZ(i,j+1); end;%Right element
bwZ(i,j) = min([ue de le re]);
%Set flag, if something has changed
if bwZ(i,j) ~= p
done = 0;
end
end
end
end
end
%Remove zero padding
bw = bwZ(2:end-1,2:end-1)
Output:
bw =
1 1 0 1 1 1 0 3
1 1 0 1 0 1 0 3
1 1 1 1 0 0 0 3
0 0 0 0 0 0 0 3
4 4 4 4 0 5 0 3
0 0 0 4 0 5 0 3
6 6 0 4 0 0 0 3
6 6 0 4 0 3 3 3
If the numbers don't need to be preserved, you can simply call bwlabel on your original image:
newImage = bwlabel(originalImage>0);
EDIT
Here's another version. It checks each connected component to see whether there's another connected component touching it. If yes, that connected component is relabelled.
%# nCC: number of connected components
nCC = max(originalImage(:));
for cc = 1:nCC
%# check whether the component exists
myCC = originalImage==cc;
if any(any(myCC))
%# create a mask to check for neighbors
%# by creating a border of 1 pixel
%# around the original label
msk = imdilate(myCC,true(3)) & ~myCC;
%# read all the pixel values under the mask
neighbours = originalImage(msk);
%# we're not interested in zeros, remove them
neighbours = neighbours(neighbours > 0);
if ~isempty(neighbours)
%# set the label of all neighbours to cc
originalImage( ismember(originalImage,neighbours) ) = cc;
end
end
end