Bootstrap

opencv绘制图形轮廓并筛选面积操作

1、 类比halcon的筛选区域面积的操作select_shape算子,opencv也可以对图形的轮廓进行面积的筛选,剔除无效区域。

int main()
{
Mat srcImage = imread("D:\\Opencv\\Project\\ConnectionProject\\modules_08.png");
imshow("【原图】", srcImage);

//首先对图像进行空间的转换  
Mat grayImage;
cvtColor(srcImage, grayImage, CV_BGR2GRAY);
//对灰度图进行滤波  
GaussianBlur(grayImage, grayImage, Size(3, 3), 0, 0);
imshow("【滤波后的图像】", grayImage);

//为了得到二值图像,对灰度图进行边缘检测  
Mat cannyImage;
Canny(grayImage, cannyImage, 128, 255, 3);
//在得到的二值图像中寻找轮廓  
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(cannyImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));


//绘制轮廓  
for (int i = 0; i < (int)contours.size(); i++)
{
drawContours(cannyImage, contours, i, Scalar(255), 1, 8);
}
imshow("【处理后的图像】", cannyImage);


//计算轮廓的面积  
cout << "【筛选前总共轮廓个数为】:" << (int)contours.size() << endl;
for (int i = 0; i < (int)contours.size(); i++)
{
double g_dConArea = contourArea(contours[i], true);
cout << "【用轮廓面积计算函数计算出来的第" << i << "个轮廓的面积为:】" << g_dConArea << endl;
}

//筛选剔除掉面积小于100的轮廓
vector <vector<Point>>::iterator iter = contours.begin();
for (; iter != contours.end();)
{
double g_dConArea = contourArea(*iter);
if (g_dConArea < 100)
{
iter = contours.erase(iter);
}
else
{
++iter;
}
}
cout << "【筛选后总共轮廓个数为:" << (int)contours.size() << endl;
for (int i = 0; i < (int)contours.size(); i++)
{
double g_dConArea = contourArea(contours[i], true);
cout << "【用轮廓面积计算函数计算出来的第" << i << "个轮廓的面积为:】" << g_dConArea << endl;
}
Mat result(srcImage.size(), CV_8U, Scalar(0));
drawContours(result, contours, -1, Scalar(255), 1);   // -1 表示所有轮廓  
namedWindow("result");
imshow("result", result);
waitKey(0);
return 0;

}

筛选前和筛选后的面积对比:

控制台输出数据:第一次轮廓面积个数为295,第二次筛选后面积个数为145,注意这里轮廓面积有正有负。

这里重点是2个算子,findcontours和drawcontours

//! retrieves contours and the hierarchical information from black-n-white image.
CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
                              OutputArray hierarchy, int mode,
                              int method, Point offset=Point());

Image必须为二值图,可以通过compare(),inRange(),threshold(),adaptiveThreshold(),Canny()这些算子来实现对原图的二值化。

contours为输出的轮廓数组,每一个轮廓用Point类型的vector容器表示。

hierarchy参数和轮廓个数相同,每一个轮廓contour[i]都包含着hieracrchy[i][0],hieracrchy[i][1],hieracrchy[i][2],hieracrchy[i][3],分别表示前一个轮廓,后一个轮廓,父轮廓,内嵌轮廓的索引编号。

mode 表示轮廓的检索模式;

RETR_EXTERNAL表示只检索最外延的轮廓。

RETR_LIST表示检测的轮廓不建立等级关系

RETR_CCOMP建立两个等级的轮廓,上面一层为外边界,里面一层为内孔边界信息,如果孔内还有一个联通物体,这个物体的边界也在顶上,

RETR_TREE建立一个等级树的轮廓,这个实例中采用这种方法。

method表示轮廓的逼近方法

CHAIN_APPROX_NONE存储所有的轮廓点,相邻两个轮廓点的位置差不超过1,

CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形只保留4个点来保存轮廓信息。

CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法 offset表示轮廓的偏移数据,可以设定任何值,在ROI中寻找轮廓,并要在这个图像中分析时,还是很有用的。

//! draws contours in the image

CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours,
                              int contourIdx, const Scalar& color,
                              int thickness=1, int lineType=8,
                              InputArray hierarchy=noArray(),
                              int maxLevel=INT_MAX, Point offset=Point() );

contouridx指明画第几个轮廓,如果该参数为负数,-1,则画全部轮廓,

color为轮廓的颜色

thickness为轮廓的线宽,如果为负数或者CV_FILLED表示轮廓内部填充。

linetype表示线型

//绘制轮廓  
for (int i = 0; i < (int)contours.size(); i++)
{
drawContours(cannyImage, contours, i, Scalar(255), 1, 8);
}
imshow("【处理后的图像】", cannyImage);

等效于以下代码:

Mat result(srcImage.size(), CV_8U, Scalar(0));
drawContours(result, contours, -1, Scalar(255), 1);   // -1 表示所有轮廓  
--------------------- 
作者:RobotHeartGo  
原文:https://blog.csdn.net/wuguanghao/article/details/69941598 
 

;