How to loop through a binary image by column to detect first 5 non-zero pixels in a row?

20 views (last 30 days)
I have a set of binary images from which I need to scan their pixel values by column. If there's exactly "x" number of non-zero pixels in a row, the algorithm needs to recognize this in order to draw a line or completely convert all pixels to "1" in the rows where this "x" non-zero pixels were identified. This is in order to close a region of the image and then calculate the area enclosed by it.
I started looping through the image and then saved the pixel values in a variable. Then I added a counter so as to count the total number of non-zero pixels from the column it's analyzing. However I'm having trouble with this loop for the part where it needs to count 5 non-zero pixels in a row. If it's followed by a zero pixel, then it's where the closing should happen, but if it's followed by yet another non-zero pixel, it means it isn't the region of interest. This is what I have so far, but it's doing nothing to the image:
[rows,columns] = size(I3);
cont = 0;
for column = 1:columns
for row = 1:rows
pixel = I3(row,column);
if (pixel == 1)
cont = cont+1;
end
if (pixel == 0)
cont = 0;
end
if (cont == 5)
if pixel == 1
cont = 0;
end
if pixel == 0
I3(row,columns) = 1;
break
end
end
end
end
figure
imshow(I3)
Thanks in advance. My matlab skills are just basic and so I have trouble with these kinds of loops.
Any help is greatly appreciated.
  3 Comments
DGM
DGM on 20 Sep 2021
Edited: DGM on 20 Sep 2021
Your problem statement seems contradictory. If the following are true:
  • the image is binary
  • you are finding runs of nonzero pixels
  • you are converting certain runs to 1
then nothing is being done by the algorithm. All nonzero pixels in a binary image are already 1. You'll need to clarify what you mean. Are the images not binary? Do you mean to find runs of zero pixels? Do you mean to convert runs of nonzero pixels to zero? Are you operating on a mix of binary and numeric images?
It's also a bit unclear what the orientation is supposed to be. You mention working "columnwise" and finding runs "in a row". This wording is potentially contradictory. Are the runs column subvectors or row subvectors?
Either way, I doubt this needs loops. Consider the example using the following assumptions:
  • binary image
  • find nonzero pixel runs
  • set target runs to zero
  • runs are column subvectors
% generate a binary test image
rng(1234);
A = rand(20,20) > 0.5;
n = 5; % number of pixels to match
% padding the array deals with runs that terminate
% on the edges of the image
A = padarray(A,[1 0],0,'both');
% find ones runs of length = n
dA = diff(A(:));
st = find(dA == 1);
en = find(dA == -1);
st = st((en-st) == n);
% generate output, setting specified runs to zero
B = A;
indexlist = cell2mat(arrayfun(@(x,y)[x:y],st+1,st+n,'uniform',false));
B(indexlist) = 0;
% remove padding
A = A(2:end-1,:);
B = B(2:end-1,:);
% display combined image to indicate changes
% yellow regions are pixels which have been removed
imshow(im2double(cat(3,A,A,B)))
There are probably simpler ways to approach whatever needs to be done, but without having the problem statement clarified, I'm not going to assume too much just yet.
Hugo Armando Morales Solís
Edited: Hugo Armando Morales Solís on 21 Sep 2021
Hi, sorry for the confusion.
My set of binary images look like this. I want to close the upper region in order to calculate the area of the triangle-like form (it's a representation of the tear film meniscus). The algorithm I'm implementing has to be able to identify the upper limit of the tear meniscus by reading columnwise every pixel. If there's only 2 non-zero pixels followed by zero pixels, then it means it's on the tear film meniscus interface (upper limit, which you can see on the image on the part where there's like a long rectangle). It's 2 pixels instead of the 5 I previously mentioned.
It's also a bit unclear what the orientation is supposed to be. You mention working "columnwise" and finding runs "in a row". This wording is potentially contradictory. Are the runs column subvectors or row subvectors?
Yeah, sorry for the wording. The runs are column subvectors. It needs to find exactly 2 continous non-zero pixels columnwise. If it encounters more than 2 continuous non-zero pixels then it means we are on the tissue region and NOT on the upper interface region. Once the algorithm is able to identify this, then it DRAWS a line (non-zero pixels) throughout the row where it first encounters that condition (two non-zero pixels) in order to close the triangle.
I have an updated algorithm which seems to work for some images, but in others, the line it draws is above where it needs to be. It seems it's some problem with the code but I'm stuck. The updated code looks like this:
[rows,columns] = size(I3); % Image size
cont = 0; % Initialize counter
flag = 0; % Initialize flag
for j = 1 : columns % Horizontal reading
for i = 1 : rows % Vertical reading
if I3(i,j) == 1
cont = cont+1;
end
if I3(i,j) == 0
cont = 0;
end
if cont > 2
break;
else
if cont == 2
I3(i,:) = 1;
flag = 1;
break;
end
end
if flag == 1
break;
end
end
end
figure
imshow(I3);
When I apply this code to the image above, it draws a line like this:
Which is more or less what I want but I think the code still has some structure problems. I think something's missing in order to clearly detect that upper boundary with the 2-non zero pixel condition, since for other images, the line is drawn way above the region it needs to be closed.
I hope this cleared the confusion a bit. Thanks for any help!

Sign in to comment.

Accepted Answer

Harikrishnan Balachandran Nair
Edited: Harikrishnan Balachandran Nair on 21 Sep 2021
Hi,
I understand that you are trying to do a column-wise traversal on your image, and see if in any column there are two continuous non zero pixels, and if there are more than 2 continuous non zero pixels, you will skip to the next column.
In that case, you might want to reset the counter value to zero before traversing the next column.
Also, if two continuous non zero pixels are found, the value of the next pixel in the column should be checked before making the pixels in the corresponding row as one.
The following code might help .
[rows,columns] = size(I3); % Image size
cont = 0; % Initialize counter
for j = 1 : columns % Horizontal reading
cont=0;
for i = 1 : rows % Vertical reading
if(I3(i,j)==0)
cont=0;
else
cont=cont+1;
if(cont==2)
if(i==rows||I3(i+1,j)==0) %checking if third there is a third non zero pixel
I3(i,:)=1;
end
break
end
end
end
end
figure
imshow(I3);
Alternatively, you can directly use the 'diff' function in matlab to see if the adjacent pixels in the column are of same value or not.
  1 Comment
Hugo Armando Morales Solís
Thank you so very much! It worked. The only thing I added was the flag that I had on my previous code in order to break from both loops, since if I didn't add it, there were some images where the line was drawn more than once in different locations.
Again, thanks for taking the time to help! Have a great day

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!