前边讲到前景检测后形态学处理,滤除大部分孤立噪点,并且能够将距离相近,属于同一目标的区域连接在一起。
在进行形态学处理后,二值图上分布着为数不多的亮点连通区域。在我们的思维里,每个连通区域隶属于同一个目标,但是计算机并不知道,在计算机眼里,它依然是一幅图像,是一个规则的二维矩阵,是分布着黑点亮点的二维矩阵。
连通区域的标记
将每团亮点标记为一个目标,暂时有两种方式可以考虑:
opencv查找轮廓函数
void findContours( InputOutputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset=Point());
连通域标记
连通域标记指的是将符合某种空间关系的像素,归属在同一个目标。常见连通域关系有四邻和八邻连通区域标记。具体空间关系如下,连通区域识别代码网上很多,不再列举。
连通区域合并
笔者采用opencv的查找轮廓函数,毕竟一些成熟的算法,必然有它恒久存在的原因。
在进行连通域标记之后,会存在这样的情形:一个目标被标记为多个连通区域。
试着分析一下原因:前景检测直接得到离散点的二值图像,目标只是分布比较密集的区域,但并不是彻底的连接成为一体。
形态学操作腐蚀、膨胀,也会影响这些离散点的连通关系。一味的增大膨胀核大小可以减少这个问题,但是会存在目标区域不精确、噪点被多重放大的风险。因此,在进行区域标记后,增加区域合并功能。
合并区域思考两个问题:
- 哪种情况需要合并?
- 怎样合并?
第一个问题,在区域标记后,我们所具有的信息只是单纯的二值点,和目标的特征分离。因此合并条件只需考虑这些被标记的连通区域的空间关系:距离相近、相交、包含(包含是特殊的相交关系)。
关于矩形相交关系,笔者分享一种判断方式:
bool CPOS::isRectOverlap(cv::Rect& rec1, cv::Rect& rec2)
{
int rec1_left, rec1_right, rec1_top, rec1_bottom;
int rec2_left, rec2_right, rec2_top, rec2_bottom;
rec1_left = rec1.x;
rec1_right = rec1.x + rec1.width;
rec1_top = rec1.y;
rec1_bottom = rec1.y + rec1.height;
rec2_left = rec2.x;
rec2_right = rec2.x + rec2.width;
rec2_top = rec2.y;
rec2_bottom = rec2.y + rec2.height;
return !(rec1_left > rec2_right || rec1_top > rec2_bottom || rec2_left > rec1_right || rec2_top > rec1_bottom);
}
至于如何合并,两个矩形求并集就可以。具体代码暂时不上传,因为在工程中用。如果有需要可以小窗口我。