Color discrimination of matrix connected components - matlab

In Matlab, I have a matrix M, say:
M=[0 0 2 2 0 0
0 0 2 2 0 3
1 1 2 2 3 3
1 1 0 0 0 0
1 1 0 0 0 0];
with some connected components labeled 1,2 and 3.
I need to discriminate the components (1, 2 and 3) by using different colors (red, green and blue for example). Any help to do this. Thanks in advance

You can use image and colormap. From the documentation of the former,
image(C) displays the data in array C as an image. Each element of C
specifies the color for 1 pixel of the image.
When C is a 2-dimensional m-by-n matrix, the elements of C are used as
indices into the current colormap to determine the color. For 'direct' CDataMapping (the default),
values in C are treated as colormap indices (1-based if double, 0-based
if uint8 or uint16).
Thererfore, you only need to call image(M+1), so that the values start at 1; and then define a suitable colormap. The colormap is a 3-column matrix, where each row defines a color in terms of its R, G, B components.
M = [0 0 2 2 0 0;0 0 2 2 0 3;1 1 2 2 3 3;1 1 0 0 0 0;1 1 0 0 0 0];
imagesc(M+1) % add 1 so that values start at 1, not 0
cmap = [1 1 1; % white
.7 0 0; % dark red
0 .7 0; % dark green
0 0 .7]; % dark blue
colormap(cmap) % set colormap
axis tight % avoid white space around the values
axis equal % aspect ratio 1:1

Related

How to add legend in a highlighted graph?

I want to add legend in a graph G according to different highlighted edges. Is it possible to do it with only one graph G?
Here is a toy example to play with. I have a plot G.
adj =[0 0 1 1 1; % adjacency matrix
1 0 1 0 1;
0 1 0 1 1;
1 1 1 0 1;
0 0 1 0 0]
G = digraph(adj);
I highlighted all edges with 3 colors according to types of edges. 3 types of edges indicate there are 3 different relation between nodes in my case.
This is how I highlighted all edges:
M(:,:,1)=[0 0 1 0 0;1 0 0 0 1;0 0 0 0 0;1 0 0 0 0;0 0 1 0 0];
M(:,:,2)=[0 0 0 1 0; 0 0 1 0 0;0 1 0 0 1;0 0 0 0 0;0 0 0 0 0];
M(:,:,3)=[0 0 0 0 1; 0 0 0 0 0; 0 0 0 1 0;0 1 1 0 1;0 0 0 0 0];
The difficulty in my problem is that I have to remove vertices whose out-degree is less than some integel (say it's 2). Thus I can't plot 3 graphs independently.
rmvNode=find(outdegree(G)<2); % outdegree is the reason why single G is neccesary
adj(rmvNode,:)=[]; adj(:,rmvNode)=[];
M(:,rmvNode,:)=[]; M(rmvNode,:,:)=[];
G=digraph(adj);
Then we can plot it.
for k=1:3 %Looping depending on the third dimension
[r,c]= find(M(:,:,k)); %Finding non-zero elements
s{k}=r; t{k}=c;
end
h=plot(G);
highlight(h,s{1},t{1},'EdgeColor','r');
highlight(h,s{2},t{2},'EdgeColor','g');
highlight(h,s{3},t{3},'EdgeColor','b');
My ideal situation would be a legend like this: assign red edges to label 'type 1', assign blue edges to 'type 2', and assign green ones to 'type 3'. I want something like this:
Once more: I can't plot 3 graphs independently according to 3 pages in M, combine 3 plots together and then add a legend. Because as you can see, outdegree requires a whole graph G as input, it's not viable to divide G into G1, G2 and G3.
One way would be to manipulate the legend function by adding an invisible plot like this:
%put this at the end of your code
hold on; %to retain current plot
ax=plot(NaN,NaN,'r',NaN,NaN,'g',NaN,NaN,'b'); %plotting invisible points of desired colors
legend(ax,'Type 1','Type 2','Type 3'); %adding the legend
which gives:

MATLAB calculate area of shape on plot

I Create a plot using imagesc. The X/Y axis are longitude and latitude respectively. The Z values are the intensity of the images for the image shown below. What I'd like to be able to do is calculate the area in each of the polygons shown. Can anybody recommend a straightforward (or any) method in accomplishing this?
EDIT
Forgot to include image.
Below is a toy example. It hinges on the assumption that the Z values are different inside the objects from outside (here: not 0). Also here I assume a straight divider at column 4, but the same principle (applying a mask) can be applied with other boundaries. This also assumes that the values are equidistant along x and y axes, but the question does not state the opposite. If that is not the case, a little more work using bsxfun is needed.
A = [0 2 0 0 0 2 0
3 5 3 0 1 4 0
1 4 0 0 3 2 3
2 3 0 0 0 4 2
0 2 6 0 1 6 1
0 3 0 0 2 3 0
0 0 0 0 0 0 0];
area_per_pix = 0.5; % or whatever
% plot it
cm = parula(10);
cm(1, :) = [1 1 1];
figure(1);
clf
imagesc(A);
colormap(cm);
% divider
dv_idx = 4;
left_object = A(:, 1:(dv_idx-1));
left_mask = left_object > 0; % threshold object
num_pix_left = sum(left_mask(:));
% right object, different method
right_mask = repmat((1:size(A, 2)) > dv_idx, size(A, 1), 1);
right_mask = (A > 0) & right_mask;
num_pix_right = sum(right_mask(:));
fprintf('The left object is %.2f units large, the right one %.2f units.\n', ...
num_pix_left * area_per_pix, num_pix_right * area_per_pix);
This might be helpful: http://se.mathworks.com/matlabcentral/answers/35501-surface-area-from-a-z-matrix
He has not used imagesc, but it's a similar problem.

How can I put margins in an image?

I have a binary image of 18x18 pixels and I want to put margins around this image with the purpose of obtaining an image 20x20 pixels.
The image is binary and it can be represented by a matrix of 1s and 0s. The 0 pixels are in black colour and the 1 pixels are in white colour. I need to put margins of 1 pixel of zeros around the image that I have.
How can I do it?
The padarray function from the image processing toolbox can be used for this purpose:
B=padarray(A,[1,1])
A=ones(18,18);%// your actual image
[M,N] = size(A);
B = zeros(M+2,N+2);%// create matrix
B(2:end-1,2:end-1) = A; %// matrix with zero edge around.
This first gets the size of your image matrix, and creates a zero matrix with two additional columns and rows, after which you can set everything except the outer edges to the image matrix.
Example with a non-square matrix of size [4x6]:
B =
0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 0
0 1 1 1 1 1 1 0
0 1 1 1 1 1 1 0
0 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0
Let's get hackish:
%// Data:
A = magic(3); %// example original image (matrix)
N = 1; %// margin size
%// Add margins:
A(end+N, end+N) = 0; %// "missing" values are implicitly filled with 0
A = A(end:-1:1, end:-1:1); %// now flip the image up-down and left-right ...
A(end+N, end+N) = 0; %// ... do the same for the other half ...
A = A(end:-1:1, end:-1:1); %// ... and flip back
First make a matrix of 20 by 20 zeroes, Zimg, then insert your image matrix into the matrix of zeroes:
Zimg(2:end-1,2:end-1)=img;

How to color a matrix?

I have a matrix in matlab of the following form:
A=[1 1 1 -1 -1
0 1 0 1 0
0 1 1 1 1
2 2 0 1 2
2 2 2 2 -1]
This matrix represents a map in the plane. Every A(i, j) is a cell in this map. I want to give color to each cell according to its number. So:
If(A(i, j)<=0)
color(A(i, j)) with black
Elseif(A(i, j)==k)
color(A(i, j)) with color k other than black
end
How to do this in matlab? Any suggestions please?
You can define a number of colours that you want using hsv or manually.
hsv(3)
ans =
1 0 0
0 1 0
0 0 1
Then use colormap to specify the color map.
colormap(hsv(3))
and then use imagesc
imagesc(A)
If you want to specify the colour also it is easy:
a = hsv(3)
a(1,:) = 1; % make the first color white
a(3,:) = 0; % make the last color black
a =
1 1 1
0 1 0
0 0 0
colormap(a)
imagesc(A)

How can I find local maxima in an image in MATLAB?

I have an image in MATLAB:
y = rgb2gray(imread('some_image_file.jpg'));
and I want to do some processing on it:
pic = some_processing(y);
and find the local maxima of the output. That is, all the points in y that are greater than all of their neighbors.
I can't seem to find a MATLAB function to do that nicely. The best I can come up with is:
[dim_y,dim_x]=size(pic);
enlarged_pic=[zeros(1,dim_x+2);
zeros(dim_y,1),pic,zeros(dim_y,1);
zeros(1,dim_x+2)];
% now build a 3D array
% each plane will be the enlarged picture
% moved up,down,left or right,
% to all the diagonals, or not at all
[en_dim_y,en_dim_x]=size(enlarged_pic);
three_d(:,:,1)=enlarged_pic;
three_d(:,:,2)=[enlarged_pic(2:end,:);zeros(1,en_dim_x)];
three_d(:,:,3)=[zeros(1,en_dim_x);enlarged_pic(1:end-1,:)];
three_d(:,:,4)=[zeros(en_dim_y,1),enlarged_pic(:,1:end-1)];
three_d(:,:,5)=[enlarged_pic(:,2:end),zeros(en_dim_y,1)];
three_d(:,:,6)=[pic,zeros(dim_y,2);zeros(2,en_dim_x)];
three_d(:,:,7)=[zeros(2,en_dim_x);pic,zeros(dim_y,2)];
three_d(:,:,8)=[zeros(dim_y,2),pic;zeros(2,en_dim_x)];
three_d(:,:,9)=[zeros(2,en_dim_x);zeros(dim_y,2),pic];
And then see if the maximum along the 3rd dimension appears in the 1st layer (that is: three_d(:,:,1)):
(max_val, max_i) = max(three_d, 3);
result = find(max_i == 1);
Is there any more elegant way to do this? This seems like a bit of a kludge.
bw = pic > imdilate(pic, [1 1 1; 1 0 1; 1 1 1]);
If you have the Image Processing Toolbox, you could use the IMREGIONALMAX function:
BW = imregionalmax(y);
The variable BW will be a logical matrix the same size as y with ones indicating the local maxima and zeroes otherwise.
NOTE: As you point out, IMREGIONALMAX will find maxima that are greater than or equal to their neighbors. If you want to exclude neighboring maxima with the same value (i.e. find maxima that are single pixels), you could use the BWCONNCOMP function. The following should remove points in BW that have any neighbors, leaving only single pixels:
CC = bwconncomp(BW);
for i = 1:CC.NumObjects,
index = CC.PixelIdxList{i};
if (numel(index) > 1),
BW(index) = false;
end
end
Alternatively, you can use nlfilter and supply your own function to be applied to each neighborhood.
This "find strict max" function would simply check if the center of the neighborhood is strictly greater than all the other elements in that neighborhood, which is always 3x3 for this purpose. Therefore:
I = imread('tire.tif');
BW = nlfilter(I, [3 3], #(x) all(x(5) > x([1:4 6:9])) );
imshow(BW)
In addition to imdilate, which is in the Image Processing Toolbox, you can also use ordfilt2.
ordfilt2 sorts values in local neighborhoods and picks the n-th value. (The MathWorks example demonstrates how to implemented a max filter.) You can also implement a 3x3 peak finder with ordfilt2 with the following logic:
Define a 3x3 domain that does not include the center pixel (8 pixels).
>> mask = ones(3); mask(5) = 0 % 3x3 max
mask =
1 1 1
1 0 1
1 1 1
Select the largest (8th) value with ordfilt2.
>> B = ordfilt2(A,8,mask)
B =
3 3 3 3 3 4 4 4
3 5 5 5 4 4 4 4
3 5 3 5 4 4 4 4
3 5 5 5 4 6 6 6
3 3 3 3 4 6 4 6
1 1 1 1 4 6 6 6
Compare this output to the center value of each neighborhood (just A):
>> peaks = A > B
peaks =
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 1 0
0 0 0 0 0 0 0 0
or, just use the excellent: extrema2.m