在[二值图像分析:连通组件寻找算法]中分享了OpenCV中对于二值图像连通组件信息提取的方法,在[二值图像分析:二值图像轮廓提取]中分享了轮廓相关信息提取的方法。在实际应用中,有时候需要按照噪点的面积来过滤掉一些噪声块。
1.通过轮廓提取
对于上面的问题,有一种解决办法是,通过轮廓提取来得到每个轮廓的面积,然后根据面积填充这些轮廓:
double start = static_cast<double>(getTickCount());
//轮廓提取
vector<vector<Point>> contours;
vector<Vec4i>hierarchy;
findContours(binaryImage,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
for(int i=0;i<contours.size();++i)
{
if(contourArea(contours[i])<50)
{
drawContours(srcImage,contours,i,Scalar(255,255,255),-1,8);
}
}
double end= ((double)getTickCount() - start) / getTickFrequency();
//以毫秒输出
cout << "所用时间为:" << end*1000 << "ms" << endl;
输出:
所用时间为:2499.35ms
实际上上面的代码处理的是一张1292*968像素的图片,里面有10000+的小区域块。
2.通过连通区域
Mat labels = Mat::zeros(binaryImage.size(),CV_32S);
Mat stats,centroids;
double start = static_cast<double>(getTickCount());
int labelNums = connectedComponentsWithStats(binaryImage,labels, stats, centroids,4, 4);
int w = srcImage.cols,h = srcImage.rows;
for(int row=0;row<h;++row)
{
for(int col=0;col<w;++col)
{
//获取labels每个位置的值,该值就是原图中对应位置像素点所属的连通区域类标签
int label = labels.at<int>(row,col);
if(label == 0) //label=0为背景区域,不用管
continue;
if(stats.at<int>(label,CC_STAT_AREA)<50)
{
srcImage.at<Vec3b>(row,col)=Vec3b(255,255,255);
}
}
}
double end= ((double)getTickCount() - start) / getTickFrequency();
//以毫秒输出
cout << "所用时间为:" << end*1000 << "ms" << endl;
输出:
所用时间为:56.5649ms
可以看出,对于同样的图像要完成按面积过滤噪声块,连通区域分析处理起来更快更高效。