本文实现的是一种比较基础的轮廓标记方法:
(1)首先寻找不为零的像素点,即像素值为value=255。
(2)对当前像素点分别向左、向右搜索当前行的其实坐标。
(3)对(2)中搜索到当前行的起始行坐标,分别搜索上一行、下一行value = 255的末坐标。
(4)依次循环(1)-(3)直到当前轮廓标记完毕。
(5)寻找下一个轮廓。
(6)依此类推,直到所有轮廓被标记完成。
int blob_scan(image_ctx_ptr img)
{
int w = img->w;
int h = img->h;
int i = 0;
int cur_label = 1;
int p_size = BLOB_STACK_SIZE;
static point_t blob_stack[BLOB_STACK_SIZE];
point_t* points = blob_stack;
uchar* pix = (uchar*)img->pix;
//img_show(img, "thre");
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
uchar value = pix[y * w + x];
if (value == 255)
{
int s, e;
int p_idx = 0;
int p_max = 1;
points[0].x = x;
points[0].y = y;
while (p_idx != p_max)
{
//获取栈顶元素
point_t* p = &points[p_idx++];
if (p_idx == p_size)
p_idx = 0;
//当上边行为两段,当前行为一整行
if (value != pix[p->y * w + p->x])
continue;
//当前行当前点的坐标左边连续点扫描
for (s = p->x - 1; s > 0 && pix[p->y * w + s] == value; s--);
//当前行当前点的坐标右边连续点扫描
for (e = p->x + 1; e < w && pix[p->y * w + e] == value; e++);
s = s < 0 ? 0 : s;
e = e > w - 1 ? w - 1 : e;
//标注当前点
for (i = s + 1; i < e; i++)
{
pix[p -> y * w + i] = cur_label;
}
//当前行的上一行扫描
for (i = s; i <= e; i++)
{
if ((p->y - 1) > 0 && pix[(p->y - 1) * w + i] == value)
{
if (i == e || pix[(p->y - 1) * w + i + 1] != value)
{
points[p_max].x = i;
points[p_max].y = p->y - 1;
if (++p_max == p_size)
p_max = 0;
if (p_max == p_idx)
goto kk;
}
}
}
//当前行的下一行扫描
for (i = s; i <= e; i++)
{
if ((p->y + 1) < w && pix[(p->y + 1) * w + i] == value)
{
if (i == e || pix[(p->y + 1) * w + i + 1] != value)
{
points[p_max].x = i;
points[p_max].y = p->y + 1;
if (++p_max == p_size)
p_max = 0;
if (p_max == p_idx)
goto kk;
}
}
}
}
cur_label++;
}
}
}
kk:
return cur_label;
}
实验结果:
原图:
标记过程效果图: