Just something I needed recently and haven’t found any existing standalone implementation. Algorithm description can be found on Wikipedia. Usage is quite simple:
% Where I is 1-, 2- or 3-dimensional image
[~, index] = sort(reshape(I, numel(I), 1), 1, ‘descend’);
blobs = ls_blob_detect(I, index);
/* Lindenberg's watershed-based blob detection algorithm implementation for MATLAB
Author: Stanislaw Adaszewski, 2012 */
#include <mex.h>
static void ind2sub(int nx, int ny, int nz, int idx, int *x, int *y, int *z) {
int r1 = idx % (nx * ny);
*z = idx / (nx * ny);
*y = r1 / nx;
*x = r1 % nx;
}
static int sub2ind(int nx, int ny, int nz, int x, int y, int z) {
if (x < 0 || x >= nx || y < 0 || y >= ny || z < 0 || z >= nz)
return -1;
else
return x + nx * (y + ny * z);
}
static const int ofs[][3] = {
{-1, -1, -1}, {-1, 0, -1}, {-1, 1, -1}, {0, -1, -1}, {0, 0, -1}, {0, 1, -1}, {1, -1, -1}, {1, 0, -1}, {1, 1, -1},
{-1, -1, 0}, {-1, 0, 0}, {-1, 1, 0}, {0, -1, 0},
// {0, 0, 0},
{ 0, 1, 0}, { 1, -1, 0}, { 1, 0, 0}, {1, 1, 0},
{-1, -1, 1}, {-1, 0, 1}, {-1, 1, 1}, {0, -1, 1}, {0, 0, 1}, {0, 1, 1}, {1, -1, 1}, {1, 0, 1}, {1, 1, 1}
};
void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
if (nlhs != 1 || nrhs != 2 || mxGetNumberOfDimensions(prhs[0]) > 3 || !mxIsDouble(prhs[0]) || mxGetClassID(prhs[1]) != mxINT32_CLASS || mxGetNumberOfElements(prhs[1]) != mxGetNumberOfElements(prhs[0])) {
mexErrMsgTxt("Usage: R=ls_blob_detect(I, index)nI must be 1-, 2- or 3-dimensional imagenindex must be list of voxel offsets (0-based) in decreasing brightness order");
return;
} else {
int N = mxGetNumberOfElements(prhs[0]);
double *data1 = mxGetPr(prhs[0]);
int n_blobs = 0;
const mwSize *siz = mxGetDimensions(prhs[0]);
int ndim = mxGetNumberOfDimensions(prhs[0]);
mxArray *R = mxCreateNumericArray(ndim, siz, mxINT32_CLASS, mxREAL);
int nx, ny, nz;
int *map = (int*) mxGetData(R);
int *index = (int*) mxGetData(prhs[1]); // malloc(sizeof(int) * N);
int i;
if (!R) {
mexErrMsgTxt("Out of memory.");
return;
}
plhs[0] = R;
for (i = 0; i < N; i++)
map[i] = 0;
nx = siz[0];
ny = siz[1];
if (ndim > 2)
nz = siz[2];
else
nz = 1;
for (i = 0; i < N; i++) {
int x, y, z;
int *neighbors = (int*) calloc(sizeof(int), n_blobs+1);
int j;
int blob, blob_cnt = 0;
if (!neighbors) {
mexErrMsgTxt("Out of memory.");
return;
}
if (data1[index[i]] == 0)
continue; // Ignore 0 voxels
ind2sub(nx, ny, nz, index[i], &x, &y, &z);
for (j = 0; j < 26; j++) {
int idx_neighbor = sub2ind(nx, ny, nz, x + ofs[j][0], y + ofs[j][1], z + ofs[j][2]);
if (idx_neighbor == -1)
continue; // Ignore voxels outside of volume boundaries
if (data1[idx_neighbor] > data1[index[i]])
neighbors[map[idx_neighbor]] += 1;
}
for (j = 0; j < n_blobs; j++)
if (neighbors[1+j] > 0) {
blob_cnt += 1;
blob = j;
}
if (neighbors[0]>0 || blob_cnt>1) {
map[index[i]] = 0; // background
} else if (blob_cnt > 0) {
map[index[i]] = 1 + blob; // existing blob
} else {
n_blobs += 1;
map[index[i]] = n_blobs; // new blob
}
free(neighbors);
}
}
}

My input is a 2-D grayscalce image. I follow the usage precisely and keep getting this error below.
So what’s wrong?
Thank you for sharing !
“Error using ls_blob_detect
Usage: R=ls_blob_detect(I, index)
I must be 1-, 2- or 3-dimensional image
index must be list of voxel offsets (0-based) in decreasing brightness order”
This message is displayed when one of the following conditions is true:
if (nlhs != 1 || nrhs != 2 || mxGetNumberOfDimensions(prhs[0]) > 3 || !mxIsDouble(prhs[0]) || mxGetClassID(prhs[1]) != mxINT32_CLASS || mxGetNumberOfElements(prhs[1]) != mxGetNumberOfElements(prhs[0]))
Make sure that you provide an output variable (R) on the left hand side and also that indices are integers (I mean really of integer data type, vide int32()).