What is the result of dilation of this image? - matlab

I have this following matrix:
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 0 0 0 0 0
1 0 0 0 0 1 1
1 0 0 0 0 1 1
And I want to dilate it with the following structuring element:
1 0 0
1 1 1
1 1 1
I already did dilation on Matlab but the result does not match with the one I did by hand. So I guess I missing something here. As far as I know if any '1' of the structuring element touches any of the '1' in the matrix, then it means it is a hit and the center of the current window should be set as 1. If I make dilation in such fashion I would get following (without considering edges):
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 1 1 0 0 0 0
1 1 1 0 1 1 0
1 1 1 0 1 1 1
1 0 0 0 0 1 1
But Matlab gives the following result:
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
1 1 1 0 1 1 0
1 1 1 0 1 1 1
1 1 0 0 1 1 1
Without considering edges it almost looks like my result but pixels styled with bold are '1' in my result but '0' in Matlab's result. What am I doing wrong? Pixel just below those '0's are '1's in the original image and the structuring element has '1' at that space when the center of the window is on those '0's so it is a hit and the center must be set '1' but Matlab doesn't do this. Can anyone explain me why? Am I missing something essential here?

Suppose matrix A is your image and matrix B is structuring element. You should pad the matrix A with zeroes on all sides. So let's say you have matrix C. Then you should perform Logical AND operation of C and B. The result matrix called D will be a dilated matrix. For further information, please see here.
Here is the code of Matlab which dilate image without 'imdilate' function:
clc;clearvars;close all;
%Image Dilation without using 'imdilate' function
% Matrix A is our image
A=[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 0 0 0 0 0;
1 0 0 0 0 1 1 ;
1 0 0 0 0 1 1 ];
%Structuring element
B=[1 0 0; 1 1 1; 1 1 1];
%Pad zeros on all the sides
C=padarray(A,[1 1]);
%Intialize a matrix of matrix size A with zeros
D=false(size(A));
for i=1:size(C,1)-2
for j=1:size(C,2)-2
%Perform logical AND operation
D(i,j)=sum(sum(B&C(i:i+2,j:j+2)));
end
end
display(D);
And this is my output, dilated matrix D:

Related

Removing single pixels Matlab

I have a binary image. I have several single pixels in images. Single pixels are white (1) and all of their neighborhoods are black (0). for example image below shows a single pixel (at center) and two pixels (at left-bottom):
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
1 1 0 0 0
How can I remove single pixels with morphological operations in Matlab?
I give you another option without loop, using a 2D convolution with conv2:
M = [0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
1 1 0 0 0]
C = [0 1 0
1 1 1
0 1 0]; % The matrice that is going to check if a `1` is alone or not.
%if you also want to consider the neibhbors on the diagonal choose:
%C = ones(3);
R = M.*conv2(M,C,'same')>1 %Check for the neighbors.
RESULT
R =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 0 0 0
Upon request by the OP, I'm converting my short comment into a reply:
Since you explicitly asked for morphological operations: bwmorph has a 'clean' option which is described as "Removes isolated pixels (individual 1s that are surrounded by 0s)" with an example close to yours. Have a look at the bwmorph documentation page.
As in your previous question, you can use bwboundaries:
if P is the binary image, than:
B = bwboundaries(P,8);
for k = 1:numel(B)
if size(B{k})<=2
P(B{k}(1,1),B{k}(1,2)) = 0;
end
end
So for the example above P becomes:
P =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 0 0 0

How to do logical operations between two matrices in matlab

I have two matrices. One is PR1 an identity matrix and another inverse identity matrix PR2. Reference Matrix A is mentioned that can be 5x5 10x10 etc. According to that I1,I2 is created.Here it is mentioned 5x5 matrix.
The logical operations start with And= PR1 AND PR2 followed by Xor= PR1 XOR PR2.
A matrix:
A =
0 1 1 1 0
1 0 1 1 0
1 1 0 1 1
1 1 1 0 1
0 0 1 1 0
I is identity matrix
PR1 =
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
PR2 =
0 0 0 0 1
0 0 0 1 0
0 0 1 0 0
0 1 0 0 0
1 0 0 0 0
And =
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
Xor =
1 0 0 0 1
0 1 0 1 0
0 0 0 0 0
0 1 0 1 0
1 0 0 0 1
Now scan left to right of each row in And and Xor matrices. Place the first 1 as it is in the new row that is in R1 matrix. Trace for second one and do NOR operation between first one 1 row and second 1 row in A matrix in above matrix (1,5) is second 1 place so do NOR operation between 1st and 5th row place the answer in R1matrix. Similarly it has R1.
R1 =
1 0 0 0 1
0 0 0 0 0
0 0 1 0 0
0 1 0 0 0
1 0 0 0 1
Now replace R1 to PR2
new
PR2 =
1 0 0 0 1
0 0 0 0 0
0 0 1 0 0
0 1 0 0 0
1 0 0 0 1
Again repated same process PR1 AND PR2 followed by PR1 XOR PR2
And =
1 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 1
Xor =
0 0 0 0 1
0 1 0 0 0
0 0 0 0 0
0 1 0 1 0
1 0 0 0 0
Now scan left to right of each row in And and Xor matrices. Place the first 1 as it is in the new row that is in R1 matrix. Trace for second one and do NOR operation between first one 1 row and second 1 row in A matrix in above matrix (1,5) is second 1 place so do NOR operation between 1st and 5th row place the answer in R2matrix.
R2=
1 0 0 0 1
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
1 0 0 0 1
check all column has minimum one 1 and stop
PR1 AND PR2 is the same as: PR1 * PR2
C = xor(A,B)
(source).
Finding the identity matrix there is a build in function. Identity matrix (I believe that is it, I don't know why it is called "eye")
You should really google stuff, like: "xor matlab matrix". There really isn't much thinking involved with getting these. You probably put more effort into writing your question.
That is quite straight forward
PR1 = eye(size(A,1));
PR2 = flip(PR1);
AND = and(PR1,PR2);
XOR = xor(PR1,PR2);
k = find(And~=0,1,'first');
R1 = zeros(size(A,1));
R1(k) = And(k);
idx = find(Xor~=0, 1, 'first');
R1(idx) = Xor(idx);
and if you want to do the NOR operations for row 1 and row 5 then you do
R1(1,:) = !(or(A(1,:),A(5,:)))
R1(2,:) = !(or(A(2,:),A(4,:)))
R1(4,:) = !(or(A(2,:),A(4,:)))
R1(5,:) = !(or(A(1,:),A(5,:)))
PR2 = R1
from here repeat your process as you need.

How do I create random matrix where each column is all zeroes except for one random row?

I want to create a matrix of size m-by-n where all elements in a column are 0 except one element which is 1. That one element must be at a random position.
eg.
[0 1 0 0 0
0 0 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 0 0 1]
To add some variety, here's another approach:
m = 4;
n = 5;
[~, result] = sort(rand(m,n));
result = double(result==1);
This gives, for example,
result =
0 0 0 0 1
0 1 0 0 0
1 0 0 1 0
0 0 1 0 0
You can also use rand and max to do the job:
m=4;
n=5;
R=rand(m,n);
result = bsxfun(#eq, R, max(R,[],1))
On my machine it gave:
1 1 0 0 0
0 0 0 0 0
0 0 1 0 1
0 0 0 1 0
How it works: Generating a random matrix, R, and then setting to 1 the entry corresponding to the maximal element at each column. No need for sorting.
Regarding the original answer of Divakar, since it uses randperm it is restricted to square matrix only, and it will only produce random permutation matrices.
One possible way to correct his solution is to use randi instead of randperm:
result = bsxfun( #eq, (1:m)', randi(m, 1, n ) )
May give this output:
1 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 1 1
As for the answer of bla, using accumarry can save the use of zeros and sub2ind:
m=5; n=10;
R=randi(m,n,1);
A = accumarray( {R, (1:n)' }, 1, [m n] )
May give this output:
0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0 1 0
1 0 0 1 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0
Another idea I have is to create the identity matrix of size m x m, then use randi with a range from 1 up to m to create a vector of n elements long. After, you'd use this vector to access the columns of the identity matrix to complete the random matrix you desire:
m = 5; n = 5; %// Given your example
M = eye(m);
out = M(:,randi(m, n, 1));
Here's one possible run of the above code:
out =
1 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
0 1 1 0 1
here's an example using randi:
m=5; n=10;
A=zeros(m,n);
R=randi(m,n,1);
A(sub2ind(size(A),R',1:n))=1
A =
0 0 0 0 0 0 0 1 0 1
0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 1 0 1 0
You can use sparse with randi for a one-liner, like so -
full(sparse(randi(m,1,n),1:n,1,m,n))
Sample run -
>> m = 5; n = 6;
>> full(sparse(randi(m,1,n),1:n,1,m,n))
ans =
0 1 0 0 0 1
0 0 1 1 0 0
0 0 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0

matlab's imfill function seems bugged?

I need to work with imfill in Matlab (Version 2010b, 7.11.0). I now think there is a bug in the program.
The most simple example that i found here is following: (Fills the Image background (0) beginning at the position [4 3])
BW = [ 0 0 0 0 0 0 0 0;
0 1 1 1 1 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 1 1 1 0 0 0;
0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0];
imfill(BW,[4 3])
According to the specifications this should work IMHO, but I always get following message. Can anyone tell me what I am doing wrong?
??? Error using ==> iptcheckconn at 56
Function IMFILL expected its second input argument, CONN,
to be a valid connectivity specifier.
A nonscalar connectivity specifier must be 3-by-3-by- ...
-by-3.
Error in ==> imfill>parse_inputs at 259
iptcheckconn(conn, mfilename, 'CONN', conn_position);
Error in ==> imfill at 124
[I,locations,conn,do_fillholes] = parse_inputs(varargin{:});
Error in ==> test at 9
imfill(BW,[4 3])
That does not explain the problem but converting BW to a logical array does work. I'm not sure as to why it's like this though:
clear
close all
clc
BW = [ 0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0];
BW2 = imfill(logical(BW),[4 3])
BW2 =
0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
As you have already seen in the other solution by #Benoit_11, that most probably that input wasn't of logical class, which was throwing an error at you. So, you are set there!
Now, I would like to put forth a tiny bit of bonus suggestion here.
Let's suppose you have a set of seed points with their row and column IDs and you would like to fill an image with those seed points in one go. For that case,
you need to use those IDs as column vectors. Thus, if you have the row and column IDs as -
row_id = [4 3];
col_id = [3 7];
You can fill image with this -
BW = imfill(BW,[row_id(:) col_id(:)])
But, the following code would throw error at you -
BW = imfill(BW,[row_id col_id])

Matlab: sort an array to ascending order in terms of binary interpretation

The array contains binary numbers per line: one row means one binary number. They are in no order so I am trying to find a command by which I can sort them to ascending order, how to do it?
Input
>> [1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0]
ans =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
Goal: by which command I can get by the input the below output?
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
You can do it by converting to strings (num2str) and then from binary string to number (bin2dec):
[vv ii] = sort(bin2dec(num2str(data)));
data_sorted = data(ii,:);
Based on my suggestion in the comments, "you should be able to do a radix sort using sortrows on columns n down to 1.", the OP got the following code working:
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1];sortrows(A)
ans =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
And has now included Luis' cool idea for indexing.
Beaker answered in the comment "you should be able to do a radix sort using sortrows on columns n down to 1." -- and it works! Then Luis Mendo had a method to store the original positioning so putting the ideas together, vuola!
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1]
[vv ii]=sortrows(A)
A =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
vv =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
ii =
4
2
1
3