2
\$\begingroup\$

I have been assigned to implement the morphological dilation operation without using MATLAB's imdilate, and I came up with the following solution:

% -------------------------------------------------------------------------
% -> Morphological Operations
% -> Image Dilation
% -------------------------------------------------------------------------
% -------------------------------------------------------------------------
% - [Pre-Operation Code: Getting Everything Ready] -
% -------------------------------------------------------------------------
% Starting With A Clean (Workspace) And (Command Window)
clear;
clc;
% Creating A Matrix Consisting Of 0s And 1s Representing A Binary Image.
binaryImage = [ ...
 0 0 0 0 0 0
 0 0 1 1 0 0
 0 0 1 1 0 0
 0 0 0 0 0 0];
% Creating A Matrix Representing Our Structuring Element
structuringElement = [ ...
 0 1 0
 1 1 1
 0 1 0];
% Getting The Number Of Rows (Height) And The Number Of Columns (Width) Of The Binary Image
[imageRows, imageColumns] = size(binaryImage);
% Getting The Number Of Rows (Height) And The Number Of Columns (Width) Of The Structuring Element
[structuringRows, structuringColumns] = size(structuringElement);
% Creating An Empty Matrix That Will Be Used To Store The Final Processed Image
dilatedImage = zeros(imageRows, imageColumns);
ref = imdilate(binaryImage, structuringElement);
% -------------------------------------------------------------------------
% - [Dilation Operation] -
% -------------------------------------------------------------------------
% Going Over Each Row In The Binary Image
for i = 1:imageRows
 % Going Over Each Column In The Binary Image
 for j = 1:imageColumns
 % If The Current Pixel Is A Foreground Pixel (1)
 if (binaryImage(i, j) == 1)
 % Going Over Each Row In The Structuring Element
 for k = 1:structuringRows
 % Going Over Each Column In The Structuring Element
 for l = 1:structuringColumns
 % If The Current Pixel In The Structuring Element Is A Foreground Pixel (1)
 if (structuringElement(k, l) == 1)
 dilatedImage(i + k - 2, j + l - 2) = 1;
 end
 end
 end
 end
 end
end
subplot(1, 3, 1), imshow(binaryImage), title('Original Image');
subplot(1, 3, 2), imshow(dilatedImage), title('Dilated Image');
subplot(1, 3, 3), imshow(ref), title('MATLAB imdilate');

I am open to any suggestions! Thank you in advance.

asked Nov 22, 2019 at 7:06
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

I have a few different comments.

Firstly, for 2D arrays like in your example, you can simply do conv2(binaryImage,structuringElement,'same'), it's equivalent to imdilate (and about 4 times faster). That might not be acceptable for your case if you are supposed to write the code yourself though.

Next, and importantly, your code has a logic error. If your binary image has a white pixel along any edge, the results are incorrect or you get an error (if it's in the top row). This is due to your indexing into dilatedImage where i+k-2 can be less than 1, or can be larger than the number of rows in dilatedImage.

You have a lot of comments, which is better than none, but I think it's excessive here. It is very clear what this line of code does [imageRows, imageColumns] = size(binaryImage);, for example, even for people who don't know Matlab. Some of your comments make the lines very long as well.

A minor issue, I'd move the imdilate command somewhere else, that part of the code is where you are re-creating imdilate, I think it's nicer to separate the verification part.

Another minor issue is in using i and j as loop indices. Since i and j can be used for complex numbers in Matlab, by convention they are avoided as loop indices (although I do not usually worry about this).

I would put the code that does the work into its own function that takes binaryImage and structuringElement as inputs and returns dilatedImage.

The big thing here is you 6 nested for/if statements, which is hard to read and hard to code. Historically, such nested loops would have been very slow in Matlab, but nowadays it's not such a concern. One thing you should do is swap the order of the first two for loops. Matlab stores arrays in a column major format, so loop over the columns first, then the rows. This gives roughly a 20-25% speedup in my tests. Additionally, checking to remove the out-of-bounds error is also a speedup, since we only set pixels to one if they are inside the image, irregardless of the value of the structuring array. Check out this version of your loop:

for j = 1:imageColumns
 for i = 1:imageRows
 if binaryImage(i, j) == 1
 % Loop through the entries of the structuring element
 for l = 1:structuringColumns
 for k = 1:structuringRows
 % make sure the new pixel is inside the image
 if i+k-2>0 && j+l-2>0 && i+k-2<=imageRows && j+l-2<=imageColumns
 % make a white pixel if necessary
 if structuringElement(k, l)==1
 dilatedImage(i + k - 2, j + l - 2) = 1;
 end
 end
 end
 end
 end
 end
end

Of course it would be nice to avoid writing all these loops, and that can be done. This next method is only slightly faster, but to me is cleaner. The idea is to first find the white pixels, and just loop over them, for each one working out which surrounding pixels should be changed.

[rowIdx,colIdx] = find(binaryImage); % the indices of white pixels in the image
[maskRowIdx,maskColIdx] = find(structuringElement); % indices of structuring elements
% now get indices of structuring elements relative to the centre of the array
maskRowIdx = maskRowIdx - floor(structuringRows/2) - 1;
maskColIdx = maskColIdx - floor(structuringColumns/2) - 1;
dilatedImage = zeros(imageRows, imageColumns);
% loop over each white pixel in the image
for i = 1:numel(rowIdx)
 % these are just the indices of the pixel
 rI = rowIdx(i);
 cI = colIdx(i);
 % now loop over each non-zero element of the structuring array
 for j = 1:numel(maskRowIdx)
 % the position of the pixel to change is (r,c)
 r = rI+maskRowIdx(j);
 c = cI+maskColIdx(j);
 % if the pixel is inside the image, we make it a 1
 if r>0 && c>0 && r<=imageRows && c<=imageColumns
 dilatedImage(r,c) = 1;
 end
 end
end
answered Nov 29, 2019 at 4:01
\$\endgroup\$
2
  • \$\begingroup\$ Thank you a lot for the tips! By the way, what about the erosion operation implementation? Is it possible to implement it following the same code you provided just with some modifications? And what will I modify? \$\endgroup\$ Commented Dec 1, 2019 at 16:13
  • \$\begingroup\$ The simplest thing to do is just use the same code but operate on ~binaryImage instead of binaryImage, that is, swap the black and white pixels, do a dilation, swap the pixels back again. \$\endgroup\$ Commented Dec 1, 2019 at 22:24

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.