Skip to content

Instantly share code, notes, and snippets.

@Saafke
Last active March 28, 2020 21:50
Show Gist options
  • Save Saafke/b934d604dc0a7dd0b4f2036c292aee2a to your computer and use it in GitHub Desktop.
Save Saafke/b934d604dc0a7dd0b4f2036c292aee2a to your computer and use it in GitHub Desktop.
Matlab code for counting number of blobs. Also known as a connected component labeling algorithm.
% Code created by Xavier Weber
% ============= PART 1: READING AND PADDING THE IMAGE =====================
function [count,im] = countBlobs(img)
%countBlobs Counts the number of blobs: connected regions of positive
% values - and labels them.
% returns: number of blobs
% Get dimensions
h = size(img,1);
w = size(img,2);
% Pad the image with a border of 1
im = padImage(img, 1);
% labels
tag = 1;
% hashmap
hash = containers.Map;
% ============= PART 2: FIRST PASS ========================================
% FIRST PASS - ignore padding
for row = 2:h+1
for col = 2:w+1
% Current pixel is of interest - change 255 to 1 if it's binary.
if im(row,col) == 255
neighbours = [im(row,col-1) im(row-1,col-1) ...
im(row-1,col) im(row-1,col+1)];
% all neighbours are zero: new component
if nnz(neighbours) == 0
im(row,col) = tag; %give it a label
tag = tag+1; %increment label
% only one neighbour is non-zero
elseif nnz(neighbours) == 1
index = find(neighbours); %get index of non-zero neighbour
im(row,col) = neighbours(index); %set current pixels to neighbour's label
% more than one neighbour is non-zero - tricky part
else
% get non-zero indexes
indices = find(neighbours);
% set it to a label of the lowest number
l = min(neighbours(indices));
im(row,col) = l;
% record equivalence classes
for i = 1:length(indices) % loop over all non-zero neighbours
templ = neighbours(indices(i)); % get its label
s = int2str(l); % convert label to string cuz hashmap
if templ ~= l % we only look at differing labels - e.g. 2->2 is not helpful
if isKey(hash,s) % already in hashmap
hash(s) = unique([hash(s) templ]);
else
hash(s) = templ;
end
end
end
end % second if
end % first if
end % col
end % row
% ============= PART 3: RESTRUCTURE HASHMAP ===============================
% Handle equivalences: restructure hashmap so that no key is a value and no
% values is a key. Basically we don't want: 12->13 and 13->14-15. We want
% it like 12->14-15.
for k = keys(hash)
if isKey(hash,k)
thekey = k{1}; % curly braces for key
array = hash(thekey);
x=1;
len = length(array);
% loop over current value array
while x <= len
% current value at index x
cur = array(x);
% see if value is its own key. E.g. 12->13 and also 13->14-15. The value 13 is also a key somewhere else.
if isKey(hash, int2str(cur)) % the key exists
% get value array of that key
array2 = hash(int2str(cur));
% put all those values in current value array. Create 12->14-15
array = [array array2];
% update hashmap
hash(thekey) = array;
% update while loop stats
x = 1; len = length(array);
% remove this key
remove(hash, int2str(cur));
else
x = x+1;
end
end
end
end
% Create the inverse mapping, will be easier for re-labelling.
% Because now we have keys like: 15->13-12-9. We want 13->15, 12->15, 9->15.
newhash = containers.Map;
for k = keys(hash)
varray = hash(k{1}); %values
for i = 1:length(varray) %loop over values
newhash(int2str(varray(i))) = str2num(k{1});
end
end
% ============= PART 4: REMOVE PADDING ====================================
% Remove padding from image
im = im(2:h+1, 2:w+1);
% ============= PART 5: SECOND PASS =======================================
% SECOND PASS - Relabel whole image
for row = 1:h
for col = 1:w
p = im(row,col);
if isKey(newhash,int2str(p))
im(row,col) = newhash(int2str(p)); % set proper label
end
end
end
% Get number unique values - these will be the count of blobs.
count = length(unique(im))-1; % zero is not a label so: minus 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment