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