I need to recognize objects in binary image.
I have searched on the internet looking for possible algorithms, there are a lot of them, but unfortunately it is very hard to personally for me convert raw formula to the code algorithm without any visual explanation.
I have found this algorithm http://www.izbi.uni-leipzig.de/izbi/publikationen/publi_2004/IMS2004_JankowskiKuska.pdf .
Furthermore there is Java
implementation described in this article.
As the author wrote
The method labelImage is now available for use as any Mathematica built-in or user-defined function
Unfortunately not, this algorithm will fail in case of 1
in corners, first,last positions because of missing if checks.
The algorithm is quite easy if we found cell with 1
and it is not labeled already we check neighbors pushing on the stack found items.
But I am not sure that it works correctly.
I have modified it, added some if
checks in order not to go out of bounds.
Here it is.
public int[][] labelImage(int stackSize) {
int nRow = img.length;
int nCol = img[0].length;
int marker = 1;
int[] pos;
mStack = new SizedStack<>(stackSize);
int[][] label = new int[nRow][nCol];
for (int r = 0; r < nRow ; r++)
for (int c = 0; c < nCol; c++) {
if (img[r][c] == 0) continue;
if (label[r][c] > 0) continue;
/* encountered unlabeled foreground pixel at position r, c */
/* push the position on the stack and assign label */
mStack.push(new int[]{r, c});
label[r][c] = marker;
/* start the float fill */
while (!mStack.isEmpty()) {
pos = mStack.pop();
int i = pos[0];
int j = pos[1];
// Check if this is not first row, in this case we don't need to check top cells
if (i > 0) {
if (img[i - 1][j - 1] == 1 && label[i - 1][j - 1] == 0) {
mStack.push(new int[]{i - 1, j - 1});
label[i - 1][j - 1] = marker;
}
if (img[i - 1][j] == 1 && label[i - 1][j] == 0) {
mStack.push(new int[]{i - 1, j});
label[i - 1][j] = marker;
}
// Check if this is not the last column cell
if (j != nCol - 1) {
if (img[i - 1][j + 1] == 1 && label[i - 1][j + 1] == 0) {
mStack.push(new int[]{i - 1, j + 1});
label[i - 1][j + 1] = marker;
}
}
}
// Check if this is not first column
if (j > 0) {
if (img[i][j - 1] == 1 && label[i][j - 1] == 0) {
mStack.push(new int[]{i, j + 1});
label[i][j + 1] = marker;
}
// Check if this is not last row
if (i != nRow - 1) {
if (img[i + 1][j - 1] == 1 && label[i + 1][j - 1] == 0) {
mStack.push(new int[]{i + 1, j - 1});
label[i + 1][j - 1] = marker;
}
}
}
// Check if this is not last row
if (i != nRow - 1) {
if (img[i + 1][j] == 1 && label[i + 1][j] == 0) {
mStack.push(new int[]{i + 1, j});
label[i + 1][j] = marker;
}
// Check if this is not first column
if (j != nCol - 1) {
if (img[i + 1][j + 1] == 1 && label[i + 1][j + 1] == 0) {
mStack.push(new int[]{i + 1, j + 1});
label[i + 1][j + 1] = marker;
}
}
}
}
marker++;
}
return label;
}
}
Here is an example and results.
Consider following image
{1, 0, 0, 0, 0, 1, 0, 1},
{0, 0, 1, 1, 0, 1, 0, 0},
{0, 0, 0, 1, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 1, 1, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
And result
[1, 0, 0, 0, 0, 2, 0, 3]
[0, 0, 4, 4, 0, 2, 0, 0]
[0, 0, 0, 4, 0, 2, 0, 0]
[0, 5, 0, 4, 0, 0, 0, 6]
[0, 0, 0, 0, 0, 7, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 8]
[0, 0, 0, 0, 0, 9, 8, 8]
[0, 0, 0, 0, 0, 0, 0, 0]
The problem here is 6-th and 7-th rows (starting from 1)
As far as I can understand this algorithm uses 8-cohesion,but I thought about it in little bit other way.
Is it correctly recognized 9 as new object ? The algorithm checks neighbors in a such way (U - unchecked, C-checked , X - current cell)
C C U
C X U
C C UWhat is wrong with cell [7,8] why it is marked, where is mistake ?
All in all, I have no a lot of experience in image processing and recognition, so I would be grateful for any help or advice of better algorithm and example of using it.
Thanks.