matlab imdilate structural element origin confusion - matlab

Consider the following operation:
a =
0 0 0 0
0 1 0 0
0 0 1 0
0 0 0 0
b=imdilate(a,[1,1;1,1])
b =
0 0 0 0
0 1 1 0
0 1 1 1
0 0 1 1
The above result indicates the origin of the structual element is [2,2]. If the origin is floor((size([1,1;1,1])+1)/2)=[1,1] by the definition (http://www-rohan.sdsu.edu/doc/matlab/toolbox/images/morph4.html)
b=
1 1 0 0
1 1 1 0
0 1 1 0
0 0 0 0
What's wrong with my understanding? Thank you!

You are correct that the origin is [1,1], but the origin is in the structuring matrix (2nd input), not the image matrix a (1st input).
Think about placing element [1,1] of your 2x2 structuring matrix on the non-zero values of a and you will see how the imdilate result is correct.
The Mathworks online help has a really nice explanation of dilation.

OK,Ithink I have found the answer.
Similar to convolution, in dilation the structuring element is reflected through its center (rotated 180 degrees) before the max operation is applied.

Related

Visualize the path on the 2D square

I want to visualize all of the paths on 2D square in matlab.
This code gives me the following figure which consists of a 2D square and randomly distributed of 1 and 0.
https://i.hizliresim.com/Ey4G4D.png
Each 1's must connected with lines from top to bottom.
If there is 1, then there is a way and I have to plot line. Otherwise therre is no way and stop.
Without the boundary elements, there are 3 way for each elements. Each element can go left side, right side or down side.
The top left hand corner's element can go right and down direction.
The top right hand corner's element can go left and down direction.
This is the algorithm of the modelling.
https://i.hizliresim.com/Dy0z0y.jpg
How can I write this code ?
I am waiting your advise :)
Problem analysis
To get an information on the possible paths in your matrix/image you can use the diff function. It calculates the difference between two neighbouring matrix elements along the specified dimension.
The conditions for the existence of a path are:
The difference between the element and its neighbour must be 0
The element itself must be 1
Solution
The following matlab program will create 3 matrices containing the value 1 or true for each element with a path existing to its neighbour.
matrix = logical([1 1 1 1 0; ...
1 1 0 1 1; ...
0 0 0 1 0; ...
0 0 1 1 0])
hasPathtoRight = false(size(matrix));
hasPathtoRight(:,1:end-1) = (diff(matrix,1,2)==0) & (matrix(:,1:end-1)==1)
hasPathtoLeft = false(size(matrix));
hasPathtoLeft(:,2:end) = (diff(matrix,1,2)==0) & (matrix(:,2:end)==1)
hasPathDown = false(size(matrix));
hasPathDown(1:end-1,:) = (diff(matrix,1,1)==0) & (matrix(1:end-1,:)==1)
Result
The result for the example matrix is shown here:
matrix =
1 1 1 1 0
1 1 0 1 1
0 0 0 1 0
0 0 1 1 0
hasPathtoRight =
1 1 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 1 0 0
hasPathtoLeft =
0 1 1 1 0
0 1 0 0 1
0 0 0 0 0
0 0 0 1 0
hasPathDown =
1 1 0 1 0
0 0 0 1 0
0 0 0 1 0
0 0 0 0 0
You can use these matrices to draw the paths in a graphical display.

Matlab, why is strel non-semetrical with respect to the angle?

I was attempting to apply a closing operation to an image using a line structuring element at 8 different directions. Initially I wanted to apply it to angles in the range [0 .. 360] but I later realised that my stucturing element is symmetrical so I thought of using the range [0 .. 180] instead. However, I later realized that Matlab's structuring element function (strel) does not produce symmetrical results for angles that are 180 degrees apart. Consider:
>> strel('line', 11, 120)
ans =
Flat STREL object containing 9 neighbors.
Neighborhood:
1 0 0 0 0
1 0 0 0 0
0 1 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 1 0
0 0 0 0 1
0 0 0 0 1
>>
And:
>> strel('line', 11, 300)
ans =
Flat STREL object containing 9 neighbors.
Neighborhood:
1 0 0 0 0 0 0
0 1 0 0 0 0 0
0 1 0 0 0 0 0
0 0 1 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 1 0 0
0 0 0 0 0 1 0
0 0 0 0 0 1 0
0 0 0 0 0 0 1
I expect that the 2 structuring elements above should be symmetrical, since 300 = 120 + 180. Why is this not the case for Matlab's strel function?
Potatoes:
This is an interesting observation. If you happen to look into the implementation of the strel object in MATLAB, the lines to observe are these (in the MakeLineStrel sub-function):
theta = theta_d * pi / 180;
x = round((len-1)/2 * cos(theta));
y = -round((len-1)/2 * sin(theta));
The theta_d value is the angle in degrees you've specified, and len is the length of the line you've requested for.
The values for x and y define the integer valued "end point" of the line, and the structuring element is constructed such that it is symmetric with respect to the origin.
Due to the rounding operation here, when you specify 120 for theta_d, the pair (x,y) will be (-2, -4), but when you specify 300, (x,y) will be (3, 4). This is the root cause for the discretized line being different due to the way the angles have been represented.
Given this understanding, it would be safest to actually print the neighborhood of the structuring element and ensure that it looks right, before using it in your operation.
Hope this helps.

Determine matrix boundary without loops

I have got a 2D matrix. There is some region in the matrix where the elements are non-zero, in particular everywhere around the edge they are zero.
I plot the matrix using image as a colorplot and would like to add the curve that shows the boundary between non-zero values to zero values in the matrix. Is there any neat way to do this without loops?
This looks like a job for convhull :
To illustrate this code i'll take a dummy example :
A=zeros(10);
B=binornd(1,0.5,8,8);
A(2:end-1,2:end-1)=B
A =
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 1 1 1 1 1 1 0 0
0 0 1 1 0 0 0 0 1 0
0 0 0 1 0 0 0 1 0 0
0 1 0 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 1 0
0 0 1 0 1 1 1 1 0 0
0 1 0 1 1 1 1 0 1 0
0 0 0 0 0 0 0 0 0 0
1/ Find the locations of all non zero entries :
[row,col]=find(A);
2/ Take the convex hull of these locations
k=convhull(row,col);
3/ Plot the convex hull (I plot the non zero points aswell but in your problem it will be your image points)
plot(row(k),col(k),'r-',row,col,'b*')
Result :
Another option is using the image processing toolbox and the bwperim function. This will work if you know that your area is completely closed (i.e. has no holes in the boundary)
This is an example using a black and white image, and you have 2 options: fill the inner gaps before, or not. You can see in the result the differences.
A = imread('circles.png');
Afill=imfill(A,'holes'); % optional
Abound1=bwperim(Afill);
Abound2=bwperim(A);
imshow([A,Abound, Abound2])
You can plot one on top of the other with:
[x,y]= find(Abound2);
hold on
image(A*255) %// If A is logical, else use just A (not *255)
colormap('gray')
plot(y,x,'r.')
hold off
axis tight
If you have a gray-scale image (or a matrix with a single value in each position (2D matrix), then you can binarize it first by either:
If you know everything outside your object is EXACTLY zero
A=yourA>0;
If you want to separate your object from the background, and the background is not exactly zero by A=im2bw(yourA,level), by choosing your own level, or letting Otsu do it for you with level=graythresh(yourA)

Matlab FingerPrint Minutia Extraction

I am very interested in fingerprint verification and studying minutia extraction at present. I have found the following code online and wonder if someone would be kind enough to explain it? I have looked up centroid, regionprops etc, I understand these a little but the code below has me puzzled!
fun=#minutie;
L = nlfilter(K,[3 3],fun);
%% Termination
LTerm=(L==1);
imshow(LTerm)
LTermLab=bwlabel(LTerm);
propTerm=regionprops(LTermLab,'Centroid');
CentroidTerm=round(cat(1,propTerm(:).Centroid));
imshow(~K)
set(gcf,'position',[1 1 600 600]);
hold on
plot(CentroidTerm(:,1),CentroidTerm(:,2),'ro')
%% Bifurcation
LBif=(L==3);
LBifLab=bwlabel(LBif);
propBif=regionprops(LBifLab,'Centroid','Image');
CentroidBif=round(cat(1,propBif(:).Centroid));
plot(CentroidBif(:,1),CentroidBif(:,2),'go')
The code first filters the binary image with a neighborhood of 3x3 pixels. nfilter is a moving filter function. It will go through all the pixels in the image given as argument and apply an operation based on the values of the neighboring pixels.
I don't know the exact content of the minutie filter, but judging by the rest of the code, it probably counts the pixels with a value of 1 in the neighborhood of all 1s. In other words it will be equal to one at the end of a segment, and equal to 3 when there are 3 branches (a bifurcation).
Example:
Let a filter sum up the ones in the neighborhood, like this:
sum(block(1,1:3), block(3,1:3), block(2,1), block(2,3))*block(2, 2);
where block denotes a neighborhood around each pixel of the binary image.
In the left matrix below (if you ignore the boundary exceptions) there is one position with a one that has exactly one 1 in its 3x3 neighborhood, in the right matrix, there is one position with a one that has exactly three 1s in its 3x3 neighborhood.
[0 0 0 0 0 [0 0 1 0 0
0 0 0 0 0 0 0 1 0 0
0 0 1 0 0 1 1 1 0 0
0 0 1 0 0 0 0 1 0 0
0 0 1 0 0] 0 0 1 0 0]
The filtered output would be:
[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 3 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0] 0 0 0 0 0]
It found a termination in the left matrix, and a bifurcation in the right matrix.
The filtered image are then thresholded at the value 1 and 3, then the use of bwlabel and regionprops is somewhat mysterious to me† since bifurcations and terminations are single points, their position is simply their index. I think you could simply achieve the detection of the coordinates of the terminations and bifurcation using something like:
[It Jt]= find(L==1);
[Ib Jb]= find(L==3);
† one reason I can think of is that coordinates in images and arrays are different in matlab, and these two function output coordinates in the image format, which is easier to plot on top of the original image.

Get the indexes of the boundary cells of a subset of a matrix. Matlab

Given a matrix where 1 is the current subset
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Is there a function, or quick method to get change the subset to the boundary of the current subset?
Eg. Get this subset from 'test' above
test =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 0
0 1 1 1 1 0
0 0 0 0 0 0
In the end I just want to get the minimum of the cells surrounding a subset of a matrix. Sure I could loop through and get the minimum of the boundary (cell by cell), but there must be a way to do it with the method i've shown above.
Note the subset WILL be connected, but may not be rectangular. This may be the big catch.
This is a possible subset.... (Would pad this with a NaN border)
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1
Ideas?
The basic steps I'd use are:
Perform a dilation on the shape to get a new area which is the shape plus its boundary
Subtract the original shape from the dilated shape to leave just the boundary
Use the boundary to index your data matrix, then take the minimum.
Dilation
What I want to do here is pass a 3x3 window over each cell and take the maximum value in that window:
[m, n] = size(A); % assuming A is your original shape matrix
APadded = zeros(m + 2, n + 2);
APadded(2:end-1, 2:end-1) = A; % pad A with zeroes on each side
ADilated = zeros(m + 2, n + 2); % this will hold the dilated shape.
for i = 1:m
for j = 1:n
mask = zeros(size(APadded));
mask(i:i+2, j:j+2) = 1; % this places a 3x3 square of 1's around (i, j)
ADilated(i + 1, j + 1) = max(APadded(mask));
end
end
Shape subtraction
This is basically a logical AND and a logical NOT to remove the intersection:
ABoundary = ADilated & (~APadded);
At this stage you may want to remove the border we added to do the dilation, since we don't need it any more.
ABoundary = ABoundary(2:end-1, 2:end-1);
Find the minimum data point along the boundary
We can use our logical boundary to index the original data into a vector, then just take the minimum of that vector.
dataMinimum = min(data(ABoundary));
You should look at this as morphology problem, not set theory. This can be solved pretty easily with imdilate() (requires the image package). You basically only need to subtract the image to its dilation with a 3x3 matrix of 1.
octave> test = logical ([0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1]);
octave> imdilate (test, true (3)) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
It does not, however, pads with NaN. If you really want that, you could pad your original matrix with false, do the operation, and then check if there's any true values in the border.
Note that you don't have to use logical() in which case you'll have to use ones() instead of true(). But that takes more memory and has worse performance.
EDIT: since you are trying to do it without using any matlab toolbox, take a look at the source of imdilate() in Octave. For the case of logical matrices (which is your case) it's a simple usage of filter2() which belongs to matlab core. That said, the following one line should work fine and be much faster
octave> (filter2 (true (3), test) > 0) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
One possible solution is to take the subset and add it to the original matrix, but ensure that each time you add it, you offset its position by +1 row, -1 row and +1 column, -1 column. The result will then be expanded by one row and column all around the original subset. You then use the original matrix to mask the original subet to zero.
Like this:
test_new = test + ...
[[test(2:end,2:end);zeros(1,size(test,1)-1)],zeros(size(test,1),1)] + ... %move subset up-left
[[zeros(1,size(test,1)-1);test(1:end-1,2:end)],zeros(size(test,1),1)] + ... %move down-left
[zeros(size(test,1),1),[test(2:end,1:end-1);zeros(1,size(test,1)-1)]] + ... %move subset up-right
[zeros(size(test,1),1),[zeros(1,size(test,1)-1);test(1:end-1,1:end-1)]]; %move subset down-right
test_masked = test_new.*~test; %mask with original matrix
result = test_masked;
result(result>1)=1; % ensure that there is only 1's, not 2, 3, etc.
The result for this on your test matrix is:
result =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
Edited - it now grabs the corners as well, by moving the subset up and to the left, up and to the right, down then left and down then right.
I expect this would be a very quick way to achieve this - it doesn't have any loops, nor functions - just matrix operations.