How can I put margins in an image? - matlab

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;

Related

Color discrimination of matrix connected components

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

assigning coordinate to a matrix in MATLAB

I'm writing a MATLAB code, I encountered a problem: I have a (2N+1)*(2N+1) matrix for example 7*7. I want to assign coordinate system to it such that the matrix center is the origin of coordinate system. I mean I want to assign (0,0) to row 4 and column 4 of matrix, (1,0) to row 4 and column 5 of matrix and so on. please help me
Thank you in advance
I want to generate a line of ones in all possible directions in a square matrix like this:
0 0 0 0 0 0 0
0 0 0 0 0 0 1
0 0 0 0 0 1 0
0 0 0 1 0 0 0
0 1 0 0 0 0 0
1 0 0 0 0 0 0
0 0 0 0 0 0 0
center of matrix is the origin. this line has 30 degree from horizontal axis.
What you want is a simple mapping from the original matrix counting system to a customized one. Here I have built two cell matrices, representing the coordinates of the elements in the matrix.
Here I have done a simple mapping as follows:
for ii = 1:7
for jj=1:7
D{ii,jj} = C{ii,jj} - [4,4];
end
end
Generally, for matrix of size 2*N+1, you will do the following:
for ii = 1:2*N+1
for jj = 1:2*N+1
D{ii,jj} = C{ii,jj} - [N+1,N+1];
end
end
where C is the original matrix and D is the mapped matrix. After you well-understood what I have done here, you can then replace the for-loops with more efficient functions such as bsxfun.

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 to replace non-zero elements randomly with zero?

I have a matrix including 1 and 0 elements like below which is used as a network adjacency matrix.
A =
0 1 1 1
1 1 0 1
1 1 0 1
1 1 1 0
I want to simulate an attack on the network, so I must replace some specific percent of 1 elements randomly with 0. How can I do this in MATLAB?
I know how to replace a percentage of elements randomly with zeros, but I must be sure that the element that is replaced randomly, is one of the 1 elements of matrix not zeros.
If you want to change each 1 with a certain probability:
p = 0.1%; % desired probability of change
A_ones = find(A); % linear index of ones in A
A_ones_change = A_ones(rand(size(A_ones))<=p); % entries to be changed
A(A_ones_change) = 0; % apply changes in those entries
If you want to randomly change a fixed fraction of the 1 entries:
f = 0.1; % desired fraction
A_ones = find(A);
n = round(f*length(A_ones));
A_ones_change = randsample(A_ones,n);
A(A_ones_change) = 0;
Note that in this case the resulting fraction may be different to that intended, because of the need to round to an integer number of entries.
#horchler's point is a good one. However, if we keep it simple, then you can just multiple your input matrix to a mask matrix.
>> a1=randint(5,5,[0 1]) #before replacing 1->0
a1 =
1 1 1 0 1
0 1 1 1 0
0 1 0 0 1
0 0 1 0 1
1 0 1 0 1
>> a2=random('unif',0,1,5,5) #Assuming frequency distribution is uniform ('unif')
a2 =
0.7889 0.3200 0.2679 0.8392 0.6299
0.4387 0.9601 0.4399 0.6288 0.3705
0.4983 0.7266 0.9334 0.1338 0.5751
0.2140 0.4120 0.6833 0.2071 0.4514
0.6435 0.7446 0.2126 0.6072 0.0439
>> a1.*(a2>0.1) #And the replacement prob. is 0.1
ans =
1 1 1 0 1
0 1 1 1 0
0 1 0 0 1
0 0 1 0 1
1 0 1 0 0
And other trick can be added to the mask matrix (a2). Such as a different freq. distribution, or a structure (e.g. once a cell is replaced, the adjacent cells become less likely to be replaced and so on.)
Cheers.
The function find is your friend:
indices = find(A);
This will return an array of the indices of 1 elements in your matrix A and you can use your method of replacing a percent of elements with zero on a subset of this array. Then,
A(subsetIndices) = 0;
will replace the remaining indices of A with zero.

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