版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/abcvincent/article/details/79274468
关于opencv在图像中查找轮廓并统计的方法基本这样几个步骤:1、读取图像——2、前期处理滤波平滑等——3、分割图像,一般阈值分割——4、FindContours查找轮廓——5、统计轮廓——6、根据连通域面积大小过滤轮廓——7、染色需要显示的轮廓——8、显示图像;上个数米的程序例子是用opencv2写的,很多方法都带cv前缀,下面用opencv3进行轮廓查找并统计:
void imgContours()//轮廓查找并统计
{
//1、读取图像
Mat img=imread("D:/ImageTest/22.PNG");//加载图片
Mat dst;
//2、前期处理滤波平衡等
cv::cvtColor(img,img,COLOR_RGB2GRAY);//进行,灰度处理
//3、分割图像,一般阈值分割
threshold( img, //输入图像,原始数组 (单通道 , 8-bit of 32-bit 浮点数).
dst, //输出图像,输出数组,必须与 src 的类型一致,或者为 8-bit.
100, //分割值
255, // 使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值.
THRESH_BINARY_INV ); //阈值类型,opencv认为白色部分为被分割出来的部分
//4、FindContours查找轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
// findContours(dst,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());//最外层轮廓
findContours(dst,contours,hierarchy,RETR_CCOMP, CHAIN_APPROX_SIMPLE,Point());//所有轮廓CV_CHAIN_APPROX_SIMPLE
// findContours返回为vector<vector<Point> >的轮廓向量
//染色需要显示的轮廓
Mat dst1 = Mat::zeros(img.size(), CV_8UC3);//初始化dst
if( !contours.empty() && !hierarchy.empty() ) //开始处理
{
//遍历所有顶层轮廓,随机生成颜色值绘制给各连接组成部分
for( int idx = 0; idx >= 0; idx = hierarchy[idx][0] )
{
Scalar color( (rand()&255), (rand()&255), (rand()&255) );//随机产生颜色 rand()产生随机数
//绘制填充轮廓
drawContours(
dst1, //用来绘制轮廓的图像
contours, //指向第一个轮廓的指针
idx, //
color, //内层轮廓的颜色
CV_FILLED, //绘制轮廓的最大等级,绘制轮廓时所使用的线条的粗细度。如果值为负(e.g. =CV_FILLED),绘制内层轮廓。
8, //线条的类型
hierarchy ); //按照给出的偏移量移动每一个轮廓点坐标.
}
}
// imshow("srcImg", img);
// imshow("findcontours",dst1);
// waitKey(0);
//6、统计轮廓
//统计面积
double contour_area_tmp=0;
double contour_area_max=0;
double contour_area_min=0;
double contour_area_sum=0;
for (int i = 0; i<contours.size(); i++)
{
contour_area_tmp=fabs(contourArea(contours[i]));
if( contour_area_tmp > contour_area_max )
{
contour_area_max = contour_area_tmp; //找到面积最大的轮廓
}
contour_area_sum += contour_area_tmp; //求所有轮廓的面积和
}
contour_area_min=contour_area_max;
for (int i = 0; i<contours.size(); i++)
{
contour_area_tmp=fabs(contourArea(contours[i]));
if( contour_area_tmp< contour_area_min )
{
contour_area_min = contour_area_tmp; //找到面积最小的轮廓
}
}
double contour_area_ave = contour_area_sum/ (contours.size()+1); //求出所有轮廓的平均值
qDebug()<<"面积最大值:"<<contour_area_max;//输出计时
qDebug()<<"面积最小值:"<<contour_area_min;//输出计时
qDebug()<<"对象数量:"<<contours.size()+1;//输出计时
qDebug()<<"面积总和:"<<contour_area_sum;//输出计时
qDebug()<<"面积平均值:"<<contour_area_ave;//输出计时
for (int i = 0; i<contours.size(); i++)
{
contour_area_tmp=fabs(contourArea(contours[i]));
qDebug()<<"所有面积值:"<<i<<":"<<QString::number(contour_area_tmp,10,2);//输出计时
}
qDebug()<<"///////////////////////";//输出
//7、根据连通域面积大小对轮廓进行排序
vector<double> contoursGram;
for (int i = 0; i<contours.size(); i++)
{
contoursGram.push_back(fabs(contourArea(contours[i])));
// qDebug()<<"所有面积值:"<<i<<":"<<QString::number( contoursGram[i],10,2);//输出计时
}
sort( contoursGram.begin(), contoursGram.end());//sort函数排序
for (int i = 0; i< contoursGram.size(); i++)
{
qDebug()<<"所有面积值:"<<i<<":"<<QString::number( contoursGram[i],10,2);//输出计时
}
//8、显示图像;
// //添加文字
QString strg1=QString::number(contour_area_max,10,3);
QString str1=QString("contour_area_max:%1").arg(strg1);
QByteArray cStr1 = str1.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p1 = cStr1.data();
putText(dst1,p1, Point(30, 30),CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(0, 0, 255), 1, 8);
QString strg2=QString::number(contour_area_min,10,3);
QString str2=QString("contour_area_min:%1").arg(strg2);
QByteArray cStr2 = str2.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p2 = cStr2.data();
putText(dst1,p2, Point(30, 30*2),CV_FONT_HERSHEY_COMPLEX,0.8, Scalar(0, 0, 255), 1, 8);
QString strg3=QString::number(contours.size()+1,10,3);
QString str3=QString("contours.size:%1").arg(strg3);
QByteArray cStr3 = str3.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p3 = cStr3.data();
putText(dst1,p3, Point(30, 30*3),CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(0, 0, 255), 1, 8);
QString strg4=QString::number(contour_area_sum,10,3);
QString str4=QString("contour_area_sum:%1").arg(strg4);
QByteArray cStr4 = str4.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p4 = cStr4.data();
putText(dst1,p4, Point(30, 30*4),CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(0, 0, 255), 1, 8);
QString strg5=QString::number(contour_area_ave,10,3);
QString str5=QString("contour_area_ave:%1").arg(strg5);
QByteArray cStr5 = str5.toLocal8Bit(); // 注意,这个QByteArray 对象一定要建立
char *p5 = cStr5.data();
putText(dst1,p5, Point(30, 30*5),CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(0, 0, 255), 1, 8);
imshow("srcImg", img);
imshow("findcontours",dst1);
waitKey(0);
}
效果: