最小外接圆
函数原型—minEnclosingCircle()
void minEnclosingCircle( InputArray points,
CV_OUT Point2f& center, CV_OUT float& radius );
- points: 输入的二维点集, 可以填Mat类型或std::vector
- center: Point2f&类型的center, 圆的输出圆心
- radius: float&类型, 表示圆的输出半径
应用实例
代码
Mat srcImg = imread("D:\\1\\10.png");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
Canny(srcImg, srcImg, 100, 200);
imshow("Canny", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
Point2f center; //定义圆中心坐标
float radius; //定义圆半径
for(int i=0; i<contours.size(); i++) //依次遍历每个轮廓
{
minEnclosingCircle(Mat(contours[i]), center, radius);
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8);
circle(dstImg, center, radius, Scalar(0, 255, 0), 2, 8); //绘制第i个轮廓的最小外接圆
}
imshow("dst", dstImg);
waitKey(0);
运行结果
椭圆拟合
函数原型—fitEllipse()
RotatedRect fitEllipse( InputArray points );
- points: 输入的二维点集, 可以填Mat类型或std::vector
- 返回值: RotatedRect类旋转矩形对象
应用实例
代码
Mat srcImg = imread("D:\\1\\10.png");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
Canny(srcImg, srcImg, 100, 200);
imshow("Canny", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
vector<RotatedRect> box(contours.size());
Point2f rect[4];
for(int i=0; i<contours.size(); i++)
{
box[i] = fitEllipse(Mat(contours[i]));
//ellipse(dstImg, box[i].center, Size(box[i].size.width/2, box[i].size.height/2), box[i].angle, 0, 360, Scalar(0, 255, 0), 2, 8);
ellipse(dstImg, box[i], Scalar(0, 255, 0), 2, 8);
}
imshow("dst", dstImg);
waitKey(0);
运行结果
逼近多边形曲线
函数原型—approxPolyDP()
void approxPolyDP( InputArray curve,
OutputArray approxCurve,
double epsilon, bool closed );
- curve: 输入的二维点集, 可以填Mat类型或std::vector
- approxCurve: 多边形逼近的结果, 其类型和输入二维点集类型一致
- epsilon: 逼近的精度, 为原始曲线和近似曲线间的最大值
- closed: 如果其为真, 则近似的曲线为封闭曲线, 否则近似的曲线不封闭
应用实例
1. 当图像有缺口时,轮廓逼近后逼近为完整的图像
2. 当查找外接矩形时,先进行轮廓逼近,再查找外接矩形
代码
Mat srcImg = imread("22.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
Mat dstImg2(srcImg.size(), CV_8UC3, Scalar::all(0));
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
//Canny(srcImg, srcImg, 100, 200);
threshold(srcImg, srcImg, 200, 255, CV_THRESH_BINARY_INV);
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
vector<vector<Point>> contours_poly(contours.size());
for(int i=0; i<contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_poly[i], 15, true);
drawContours(dstImg, contours, i, Scalar(0, 255, 0), 2, 8);
drawContours(dstImg2, contours_poly, i, Scalar(0, 255, 255), 2, 8); //绘制多边形逼近
}
imshow("dst", dstImg);
imshow("approx", dstImg2);
waitKey(0);
运行结果
srcImg
thresholdImg
轮廓图
多边形趋近
计算轮廓面积
函数原型
double contourArea( InputArray contour, bool oriented = false );
- contour: 输入的二维点集或轮廓, 可以填Mat类型或std::vector
- oriented: 默认值false, 表示返回面积为绝对值, 负责带符号
返回值: double类型返回轮廓面积
代码
Mat srcImg = imread("33.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
Mat dstImg2(srcImg.size(), CV_8UC3, Scalar::all(0));
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
//Canny(srcImg, srcImg, 100, 200);
threshold(srcImg, srcImg, 200, 255, CV_THRESH_BINARY);
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
for(int i=0; i<contours.size(); i++)
{
double area = contourArea(contours[i]);
cout<<"area--"<<i<<"---"<<area<<endl;
if(area>10000) //面积大约1W
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8);
}
imshow("dst", dstImg);
waitKey(0);
计算轮廓长度(周长或者曲线长度)
函数原型—arcLength()
double arcLength( InputArray curve, bool closed );
- curve: 输入的二维点集, 可以填Mat类型或std::vector
- colsed: 用于指示曲线是否封闭的标识符, 默认值true, 表示曲线封闭
返回值: double类型返回轮廓长度
注:contourArea()&& arcLength()可用于轮廓删选
代码
Mat srcImg = imread("33.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
Mat dstImg2(srcImg.size(), CV_8UC3, Scalar::all(0));
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
//Canny(srcImg, srcImg, 100, 200);
threshold(srcImg, srcImg, 200, 255, CV_THRESH_BINARY);
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
for(int i=0; i<contours.size(); i++)
{
double length = arcLength(contours[i], true);
cout<<"length--"<<i<<"---"<<length<<endl;
if(length>300) //轮廓曲线长度大于300
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8);
}
imshow("dst", dstImg);
waitKey(0);
利用mask提取不规则轮廓
应用实例
代码
Mat srcImg = imread("D:\\1\\220.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone(); //原图备份
Mat tempImg = srcImg.clone(); //原图备份
Mat tempImg2(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定义全黑的和原图一样大小的图像
Mat draw(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定义全黑的和原图一样大小的图像
Mat tempImg3(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定义全黑的和原图一样大小的图像
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY); //二值化
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
while(1)
{
for(int i=0; i<contours.size(); i++)
{
tempImg2.copyTo(draw); //每次进入将draw清空为全黑
tempImg2 .copyTo(tempImg3); //每次进入将tempImg3清空为全黑
//drawContours(dstImg, contours, i, Scalar(0, 255, 0), 5, 8);
drawContours(draw, contours, i, Scalar(255, 255, 255), -1, 8);
Mat mask; //定义掩码
cvtColor(draw, mask, CV_BGR2GRAY);
tempImg.copyTo(tempImg3, mask); //将tempImg 复制到tempImg3(只有mask部分被复制)
imshow("draw", draw);
imshow("result", tempImg3);
char key = waitKey();
if(key==27) //按下Esc键跳出for循环
break;
}
break;
}
运行结果
srcImg
threshold
draw
result
知识点讲解
掩码
参考以前的opencv学习之掩码
dstImg,tempImg都是对原图的备份;tempImg2,draw,tempImg3都是全黑的图像
Mat dstImg = srcImg.clone(); //原图备份
Mat tempImg = srcImg.clone(); //原图备份
Mat tempImg2(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定义全黑的和原图一样大小的图像
Mat draw(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定义全黑的和原图一样大小的图像
Mat tempImg3(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定义全黑的和原图一样大小的图像
每次绘制都将draw和tempImg3清空为全黑。将轮廓(内部填充为白色)绘制到draw图像,将draw图像转为灰度的掩码图像mask,然后进行掩码的复制操作
tempImg2.copyTo(draw); //每次进入将draw清空为全黑
tempImg2 .copyTo(tempImg3); //每次进入将tempImg3清空为全黑
//drawContours(dstImg, contours, i, Scalar(0, 255, 0), 5, 8);
drawContours(draw, contours, i, Scalar(255, 255, 255), -1, 8);
Mat mask; //定义掩码
cvtColor(draw, mask, CV_BGR2GRAY);
tempImg.copyTo(tempImg3, mask); //将tempImg 复制到tempImg3(只有mask部分被复制)