我已经实现了来自here的连通组件识别算法,但似乎cv :: floodFill(...)在某些情况下填充了未连接的区域。
首先,这是代码:
void ImageMatchingOpenCV::getConnectedComponents(const cv::Mat& binImg, vector<vector<cv::Point>>& components, vector<vector<cv::Point>>& contours, const int minSize)
{
cv::Mat ccImg;
binImg.convertTo(ccImg, CV_32FC1);
int gap=startPointParams.gap;
int label = 1;
for(int y=gap; y<binImg.rows-gap; ++y)
{
for(int x=gap; x<binImg.cols-gap; ++x)
{
if((int)ccImg.at<float>(y, x)!=255) continue;
cv::Rect bBox;
cv::floodFill(ccImg, cv::Point(x, y), cv::Scalar(label), &bBox, cv::Scalar(0), cv::Scalar(0), 4 /*| cv::FLOODFILL_FIXED_RANGE*/);
if(bBox.x<gap || bBox.y<gap || bBox.x+bBox.width>=binImg.cols-gap || bBox.y+bBox.height>=binImg.rows-gap) continue;
components.push_back(vector<cv::Point>()); contours.push_back(vector<cv::Point>());
for(int i=bBox.y; i<bBox.y+bBox.height; ++i)
{
for(int j=bBox.x; j<bBox.x+bBox.width; ++j)
{
if((int)ccImg.at<float>(i, j)!=label) continue;
components.back().push_back(cv::Point(j, i));
if( (int)ccImg.at<float>(i+1, j)!=label
|| (int)ccImg.at<float>(i-1, j)!=label
|| (int)ccImg.at<float>(i, j+1)!=label
|| (int)ccImg.at<float>(i, j-1)!=label) contours.back().push_back(cv::Point(j, i));
}
}
if(components.back().size()<minSize)
{
components.pop_back();
contours.pop_back();
}
else
{
++label;
if(label==255) ++label;
break;
}
}
if(label!=1) break;
}
}
输入cv :: Mat包含大小为CV_8U的2448x2050像素。像素值为0(背景)或255(前景)。图像中有17个连接的组件。除第一个之外的所有组件都被正确识别。错误的组件是迄今为止最大的组件(约150万像素)并且包含一些小的断开连接的像素组。它包含所有其他组件。错误分配给第一个组件的小的断开连接的像素组都连接到组件边界框的顶部。
编辑:我添加了一些图像以显示问题。第一张图显示了所有已识别的连接组件。第二个图像仅显示错误的组件(注意顶部的小的断开连接的像素组)。第三个图像放大第二个图像的一部分:
如果有人有想法,错误可能在哪里,我会很感激。
答案 0 :(得分:0)
if(components.back().size()<minSize)
{
components.pop_back();
contours.pop_back();
}
else
{
++label;
if(label==255) ++label;
}
这意味着,标签编号再次用于标记图像中的下一个组件。因此,几个小组件和一个足够大的组件可能具有相同的标签号。如果现在迭代大组件的边界框,则此边界框可能包含一些先前已识别但未使用的具有相同标签编号的组件。
解决方案是删除else分支,而是始终增加标签号。