OpenCV c++ 轮廓检测

轮廓发现与绘制

findContours()用于检测轮廓信息和轮廓之间的结构信息。

                输入二值化图像

                输出vector<vector<Point>> 类型的轮廓像素坐标和vector<Vec4i>类型的轮廓结构信息。

轮廓结构信息:[同层下一个轮廓索引,同层上一个轮廓索引,下一层第一个子轮廓索引,上层父轮廓索引]

        0:[-1,-1,1,-1]     1:[2,-1,3,0]      2:[-1,1,,3,0]       3:[-1,-1,-1,2]

        


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;



int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	system("color F0");
	Mat img = imread("D:/images/circles.png");
	imshow("img", img);
	//resize(img, img, Size(img.cols / 3, img.rows / 3), 0, 0, INTER_LINEAR);
	if (img.empty()) {
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	Mat gary,binary;
	cvtColor(img, gary, COLOR_BGR2GRAY);
	GaussianBlur(gary, gary, Size(9, 9), 2, 2);
	threshold(gary, binary, 170, 255, THRESH_BINARY | THRESH_OTSU);		//自适应二值化

	//轮廓发现与绘制
	vector<vector<Point>> contours;		//轮廓
	vector<Vec4i> hierarchy;		//存放轮廓结构变量
	findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
	//绘制轮廓
	for (int t = 0; t < contours.size(); t++) {
		drawContours(img, contours, t, Scalar(0, 0, 255), 2, 8);
	}
	//输出轮廓结构描述
	for (int i = 0; i < hierarchy.size(); i++) {
		cout << hierarchy[i] << endl;
	}

	//显示图像
	imshow("轮廓检测结果", img);

	waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
	//destroyAllWindows();
	return 0;
}




轮廓面积 

contourArea(contours[t])用于统计轮廓像素点围成区域的面积,便于区分物体大小、识别物体种类。


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;



int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	system("color F0");
	vector<Point> contour;
	contour.push_back(Point2f(0, 0));
	contour.push_back(Point2f(10, 0));
	contour.push_back(Point2f(10, 10));
	contour.push_back(Point2f(5, 5));
	double area = contourArea(contour);
	cout << "area=" << area << endl;


	Mat img = imread("D:/images/circles.png");
	imshow("img", img);
	//resize(img, img, Size(img.cols / 3, img.rows / 3), 0, 0, INTER_LINEAR);
	if (img.empty()) {
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	Mat gary,binary;
	cvtColor(img, gary, COLOR_BGR2GRAY);
	GaussianBlur(gary, gary, Size(9, 9), 2, 2);
	threshold(gary, binary, 170, 255, THRESH_BINARY | THRESH_OTSU);		//自适应二值化

	//轮廓发现与绘制
	vector<vector<Point>> contours;		//轮廓
	vector<Vec4i> hierarchy;		//存放轮廓结构变量
	findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
	
	//输出轮廓面积
	for (int t = 0; t < contours.size(); t++) {
		double area1 = contourArea(contours[t]);
		cout << "第" << t << "轮廓面积=" << area1 << endl;
	}

	waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
	//destroyAllWindows();
	return 0;
}




轮廓周长

arcLength(contours[t], true)

参数一:输入像素点,数据类型为Mat或者vector<Point>

参数二:轮廓是否闭合。true--计算周长;false--计算像素点连线长度


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;



int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	system("color F0");
	vector<Point> contour;
	contour.push_back(Point2f(0, 0));
	contour.push_back(Point2f(10, 0));
	contour.push_back(Point2f(10, 10));
	contour.push_back(Point2f(5, 5));

	double length0 = arcLength(contour, true);
	double length1 = arcLength(contour, false);
	cout << "length0=" << length0 << endl;
	cout << "length1=" << length1 << endl;


	Mat img = imread("D:/images/circles.png");
	imshow("img", img);
	//resize(img, img, Size(img.cols / 3, img.rows / 3), 0, 0, INTER_LINEAR);
	if (img.empty()) {
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	Mat gary,binary;
	cvtColor(img, gary, COLOR_BGR2GRAY);
	GaussianBlur(gary, gary, Size(9, 9), 2, 2);
	threshold(gary, binary, 170, 255, THRESH_BINARY | THRESH_OTSU);		//自适应二值化

	//轮廓发现与绘制
	vector<vector<Point>> contours;		//轮廓
	vector<Vec4i> hierarchy;		//存放轮廓结构变量
	findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());

	//输出轮廓长度
	for (int t = 0; t < contours.size(); t++) {
		double length2 = arcLength(contours[t], true);
		cout << "第" << t << "轮廓长度=" << length2 << endl;
	}
	waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
	//destroyAllWindows();
	return 0;
}




轮廓外接矩形

作用:将物体轮廓不规则的形状拟合成矩形或者多边形

轮廓外接最大矩形

寻找轮廓x方向和y方向两端的像素,该矩形的长、宽分别与图像的两条轴平行。 

boundingRect(contours[t]);  

输入灰度图像或二位点集; 输出Rect类型的变量(左上角坐标,宽,高)

轮廓外接最矩形

4个边与轮廓相交,矩形旋转角度与轮廓形状有关,多数情况下不与图像的两条轴平行。 

minAreaRect(contours[t]);

输入灰度图像或二位点集; 输出RotatedRect类型变量(矩形中心位置,宽、高、旋转角度)


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;



int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	
	Mat img = imread("D:/images/rect.png");
	imshow("img", img);
	//resize(img, img, Size(img.cols / 3, img.rows / 3), 0, 0, INTER_LINEAR);
	if (img.empty()) {
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	Mat img1, img2;
	img.copyTo(img1);		//深拷贝用来绘制最大外接矩形
	img.copyTo(img2);		//深拷贝用来绘制最小外接矩形

	//去噪和二值化
	Mat canny;
	Canny(img, canny, 80, 160, 3, false);
	imshow("canny", canny);

	//膨胀 将细小缝隙填补
	Mat kernel = getStructuringElement(0, Size(3, 3));
	dilate(canny, canny, kernel);

	//轮廓发现与绘制
	vector<vector<Point>> contours;		//轮廓
	vector<Vec4i> hierarchy;		//存放轮廓结构变量
	findContours(canny, contours, hierarchy, 0, 2, Point());

	//输出轮廓的外接矩形
	for (int t = 0; t < contours.size(); t++) {
		//最大外接矩形
		Rect rect = boundingRect(contours[t]);
		rectangle(img1, rect, Scalar(0, 0, 255), 2, 8, 0);
		//最大外接矩形
		RotatedRect rrect=minAreaRect(contours[t]);
		Point2f points[4];
		rrect.points(points);		//读取最小外接矩形的4个顶点
		Point2f cpt = rrect.center;		//最小外接矩形的中心
		//绘制旋转矩形与中心位置
		for (int i = 0; i < 4; i++) {
			if (i == 3) {
				line(img2, points[i], points[0], Scalar(0, 255, 0), 2, 8, 0);
				break;
			}
			line(img2, points[i], points[i + 1], Scalar(0, 255, 0), 2, 8, 0);
		}
		//绘制矩形中心
		circle(img, cpt, 2, Scalar(255, 0, 0), 2, 8, 0);
	}
	//输出绘制结果
	imshow("max", img1);
	imshow("min", img2);
	waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
	//destroyAllWindows();
	return 0;
}




 

 轮廓外接多边形

 

用矩形逼近轮廓也时候会产生较大的误差,寻找逼近轮廓的多边形,多边形围成的面积会更加接近真实形状。

approxPolyDP(contours[t], result, 4, true);

        输入灰度图像或二位点集; 输出多边形顶点坐标的Mat类矩阵

可通过顶点数初步判断轮廓的几何形状


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;

void drawapp(Mat result, Mat img2) {
	for (int i = 0; i < result.rows; i++) {
		if (i = result.rows - 1) {
			Vec2i point1 = result.at<Vec2i>(i);
			Vec2i point2 = result.at<Vec2i>(0);
			line(img2, point1, point2, Scalar(0, 0, 255), 2, 8, 0);
			break;
		}
		Vec2i point1= result.at<Vec2i>(i);
		Vec2i point2 = result.at<Vec2i>(i+1);
		line(img2, point1, point2, Scalar(0, 0, 255), 2, 8, 0);
	}
}


int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	
	Mat img = imread("D:/images/angl.png");
	//imshow("img", img);
	//resize(img, img, Size(img.cols / 3, img.rows / 3), 0, 0, INTER_LINEAR);
	if (img.empty()) {
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	//去噪和二值化
	Mat canny;
	Canny(img, canny, 80, 160, 3, false);
	//imshow("canny", canny);

	//轮廓发现与绘制
	vector<vector<Point>> contours;		//轮廓
	vector<Vec4i> hierarchy;		//存放轮廓结构变量
	findContours(canny, contours, hierarchy, 0, 2, Point());

	//绘制多边形
	for (int t = 0; t < contours.size(); t++) {
		//用最小外接矩形求轮廓中心
		RotatedRect rrect=minAreaRect(contours[t]);
		Point2f center = rrect.center;		//最小外接矩形的中心
		circle(img, center, 2, Scalar(0, 255, 0), 2, 8, 0);

		Mat result;
		approxPolyDP(contours[t], result, 4, true);		//多边形逼近
		drawapp(result, img);
		cout << "corners:" << result.rows << endl;
		//判断形状和轮廓绘制
		if (result.rows == 3) {
			putText(img, "triangle", center, 0, 1, Scalar(0, 255, 0), 1, 8);
		}
		if (result.rows == 4) {
			putText(img, "rectangle", center, 0, 1, Scalar(0, 255, 0), 1, 8);
		}
		if (result.rows == 8) {
			putText(img, "poly-8", center, 0, 1, Scalar(0, 255, 0), 1, 8);
		}
		if (result.rows > 12) {
			putText(img, "circle", center, 0, 1, Scalar(0, 255, 0), 1, 8);
		}
	}
	//输出绘制结果
	imshow("resule", img);
	waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
	//destroyAllWindows();
	return 0;
}




 

点到轮廓的距离 

 

作用:可用于计算轮廓在图像中的位置、两个轮廓之间的距离、确定图像上某一点是否在轮廓内部。

double dis = pointPolygonTest(contours[t], point, true);

        输入:轮廓和像素点坐标 输出:像素点距离轮廓的最小距离


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;

void drawapp(Mat result, Mat img2) {
	for (int i = 0; i < result.rows; i++) {
		if (i = result.rows - 1) {
			Vec2i point1 = result.at<Vec2i>(i);
			Vec2i point2 = result.at<Vec2i>(0);
			line(img2, point1, point2, Scalar(0, 0, 255), 2, 8, 0);
			break;
		}
		Vec2i point1= result.at<Vec2i>(i);
		Vec2i point2 = result.at<Vec2i>(i+1);
		line(img2, point1, point2, Scalar(0, 0, 255), 2, 8, 0);
	}
}


int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	system("color F0");
	Mat img = imread("D:/images/angl.png");
	//imshow("img", img);
	//resize(img, img, Size(img.cols / 3, img.rows / 3), 0, 0, INTER_LINEAR);
	if (img.empty()) {
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	//去噪和二值化
	Mat canny;
	Canny(img, canny, 80, 160, 3, false);
	//imshow("canny", canny);
	//膨胀 将细小缝隙填补
	Mat kernel = getStructuringElement(0, Size(3, 3));
	dilate(canny, canny, kernel);
	//轮廓发现与绘制
	vector<vector<Point>> contours;		//轮廓
	vector<Vec4i> hierarchy;		//存放轮廓结构变量
	findContours(canny, contours, hierarchy, 0, 2, Point());

	//创建图像中的一个像素点并绘制圆形
	Point point = Point(250, 200);
	circle(img, point, 2, Scalar(0, 0, 255), 2, 8, 0);


	//绘制多边形
	for (int t = 0; t < contours.size(); t++) {
		//用最小外接矩形求轮廓中心
		RotatedRect rrect=minAreaRect(contours[t]);
		Point2f center = rrect.center;		//最小外接矩形的中心
		circle(img, center, 2, Scalar(0, 255, 0), 2, 8, 0);
		//轮廓外部点距离轮廓的距离
		double dis = pointPolygonTest(contours[t], point, true);
		//轮廓内部点距离轮廓的距离
		double dis2 = pointPolygonTest(contours[t], center, true);
		//输出结果
		cout << "轮廓外部点距离轮廓的距离" << dis << endl;
		cout << "轮廓内部点距离轮廓的距离" << dis2 << endl;
	}
	imshow("img", img);
	waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
	//destroyAllWindows();
	return 0;
}




凸包检测 

作用:对轮廓进行多边形逼近,但逼近结果一定是凸多边形

凸包:将二维平面上的点集最外层的点连接起来构成的凸多边形


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;




int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	//system("color F0");
	Mat img = imread("D:/images/hand.jpg");
	imshow("img", img);
	resize(img, img, Size(img.cols / 3, img.rows / 3), 0, 0, INTER_LINEAR);
	if (img.empty()) {
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	Mat gary, binary;
	cvtColor(img, gary, COLOR_BGR2GRAY);
	//GaussianBlur(gary, gary, Size(9, 9), 2, 2);
	threshold(gary, binary, 105, 255, THRESH_BINARY);	

	//开运算消除细小区域
	Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
	morphologyEx(binary, binary, MORPH_OPEN, k);
	imshow("binary", binary);

	//轮廓发现与绘制
	vector<vector<Point>> contours;		//轮廓
	vector<Vec4i> hierarchy;		//存放轮廓结构变量
	findContours(binary, contours, hierarchy, 0, 2, Point());
	for (int t = 0; t < contours.size(); t++) {
		//计算凸包
		vector<Point> hull;
		convexHull(contours[t], hull);
		//绘制凸包
		for (int i = 0; i < hull.size(); i++) {
			//绘制凸包顶点
			circle(img, hull[i], 4, Scalar(255, 0, 0), 2, 8, 0);
			//连接凸包
			if (i == hull.size() - 1) {
				line(img, hull[i], hull[0], Scalar(0,0 , 255), 2, 8, 0);
				break;
			}
			line(img, hull[i], hull[i+1], Scalar(0, 0, 255), 2, 8, 0);
		}
	}
	imshow("img", img);
	waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
	//destroyAllWindows();
	return 0;
}




  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值