OpenCV之图像轮廓


一、寻找轮廓findContours()

1.要层次hierarchy

原型

void findContours(
	InputArray image,
	OutputArrayOfArrays contours,
	OutputArray hierarchy,
	int mode,
	int method,
	Point offset=Point()
);

参数

  • image:输入图像。必须为8位单通道图像
  • contours:轮廓。一般为vector<vector<Point> > contours;,意思是多个点集,每个点集是一个轮廓,多个点集构成轮廓集。
  • hierarchy:层次。一般为vecotr<Vec4i> hierarchy;
  • mode:轮廓检索模式
    • RETR_EXTERNAL:
    • RETR_LIST:
    • RETR_CCOMP:
    • RETR_TREE :
  • method:轮廓的近似方法
    • CHAIN_AOOROX_NONE:
    • CHAIN_AOOROX_SIMPLE:
    • CHAIN_AOOROX_TC89_LI:
    • CHAIN_AOOROX_TC89_KCOS:
  • offset:每个轮廓点的可选偏移量

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
	//灰度图
	Mat srcImage=imread("M.jpg",0);
	
	//取阈值成二值图
	srcImage=srcImage>100;
	namedWindow("Threshold119",WINDOW_NORMAL);
	imshow("Threshold119",srcImage);
	
	Mat dstImage=Mat::zeros(srcImage.size(),srcImage.type());
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(srcImage,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
	
	waitKey();
	return 0;
}

2.不要层次hierarchy

void findContours(
	InputArray image,
	OutputArrayOfArrays contours,
	int mode,
	int method,
	Point offset=Point()
);

3.轮廓就是点集

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main()
{
	Mat src=imread("/home/volume/VSCode/imageSrc/cube.png",0);
	
	Mat point_dst;
	point_dst.create(src.rows,src.cols,CV_8UC1);
	point_dst=Scalar::all(0);
	
	Mat bounding_dst;
	bounding_dst.create(src.rows,src.cols,CV_8UC1);
	bounding_dst=Scalar::all(0);
	
	//只绘制一个点集
	vector<vector<Point> > contours;
	findContours(src,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
	for(int i=0;i<contours[0].size();i++)
	{
		//绘制每个点
		circle(point_dst,contours[0][i],1,Scalar::all(255));
	}
	
	//圈出那个轮廓
	RotatedRect rotatedRect=minAreaRect(contours[0]);
	Point2f hull[4];
	rotatedRect.points(hull);
	for(int i=0;i<4;i++)
	{
		line(bounding_dst,hull[i],hull[(i+1)%4],Scalar::all(255));
	}

	imshow("src",src);
	imshow("point_dst",point_dst);
	imshow("bounding_dst",bounding_dst);
	waitKey();

	return 0;
}

在这里插入图片描述

二、绘制轮廓drawContours()

原型

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

参数

  • image:输入图像。必须为8位单通道图像。图像必须已经创建
  • contours:轮廓。为findContours()的vector<vector<Point> > contours;
  • contourIdx:轮廓绘制的指示变量。如果为负值,则绘制所有轮廓
  • color:轮廓的颜色
  • thickness:轮廓线条的粗细度
  • lineType:轮廓线条的类型
  • hierarchy:层次结构信息
  • maxLevel:表示用于绘制轮廓的最大等级
  • offset:每个轮廓点的可选偏移量
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

# define WINDOW_NAME "Effect"

Mat g_srcImage;
vector<vector<Point> > g_contours;
vector<Vec4i> g_hierarchy;
int g_threshValue=80;
int g_threshValueMax=255;



void onChange(int,void*)
{
	//取阈值成二值图
	g_srcImage=g_srcImage>g_threshValue;
	namedWindow(WINDOW_NAME,WINDOW_NORMAL);
	imshow(WINDOW_NAME,g_srcImage);
	
	Mat dstImage=Mat::zeros(g_srcImage.size(),g_srcImage.type());

	namedWindow("dstImage",WINDOW_NORMAL);
	
	findContours(g_srcImage,g_contours,g_hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE);
	for(int index=0;index<g_contours.size();index++)
	{
		Scalar color(rand()&255,rand()&255,rand()&255);
		drawContours(dstImage,g_contours,index,color,FILLED,8,g_hierarchy);
		imshow("dstImage",dstImage);
		waitKey(1);
	}
	
}

int main()
{
	//灰度图
	g_srcImage=imread("t.jpg",0);
	namedWindow(WINDOW_NAME,WINDOW_NORMAL);
	imshow(WINDOW_NAME,g_srcImage);
	
	createTrackbar("Threshold",WINDOW_NAME,&g_threshValue,g_threshValueMax,onChange);
	onChange(0,0);

	waitKey();
	return 0;
}

在这里插入图片描述

三、寻找凸包

原型

void convexHull(
	InputArray points,
	OutputArray hull,
	bool clockkwise=false,
	bool returnPoints=true
)

参数

  • points:输入的二维点集。可以是Mat类,也可以是vector容器
  • hull:找到的凸包。凸包的数据其实是下标。
  • clockkwise:操作方向标识符。真为顺时针,假为逆时针(默认)。并且坐标系是x指右,y指上
  • returnPoints:操作标识符。真为返回各凸包的各个点(默认),假为返回凸包各点的指数。当hull是vector时,此标志被忽略。

绘制点的凸包

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define W_CONVEX "convexHull"

int main()
{
	Mat image=Mat::zeros(600,600,CV_8UC3);

	//初始化rng
	RNG& rng=theRNG();

	while(1)
	{
		char key;

		//获得一个3到103的数量
		int count=(unsigned)rng%100+3;
		vector<Point> points;

		for(int i=0;i<count;i++)
		{
			Point point;
			//在1/4到3/4区域内的正态分布点
			point.x=rng.uniform(image.cols/4,image.cols*3/4);
			point.y=rng.uniform(image.rows/4,image.rows*3/4);
			points.push_back(point);
		}

		//圈出要绘制的点
		for(int i=0;i<count;i++)
		{
			circle(image,points[i],3,Scalar::all(150),5);
		}

		//寻找凸包
		vector<int> hull;
		//凸包内数据其实是凸包的点points的下标
		convexHull(Mat(points),hull);


		//用连线表示凸包
		for(int i=0;i<hull.size();i++)
		{
			//从上一个点到下一个点
			line(image,points[hull[i]],points[hull[(i+1)%hull.size()]],Scalar::all(255),2);
		}

		namedWindow(W_CONVEX,WINDOW_NORMAL);
		imshow(W_CONVEX,image);

		//图像重新变成全黑的
		image=Scalar::all(0);

		if(waitKey()=='q') return 0;

	}

	return 0;
}

在这里插入图片描述

四、使用多边形

1.外部矩形边界boundingRect()

原型

Rect boundingRect(InputArray points)

参数

points:Mat类或者是std::vector二维点集

例子

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define W_CONVEX "RESULT"

int main()
{
	Mat image=Mat::zeros(600,600,CV_8UC3);

	//初始化rng
	RNG& rng=theRNG();

	while(1)
	{
		char key;

		//获得一个3到103的数量
		int count=(unsigned)rng%100+3;
		vector<Point> points;

		for(int i=0;i<count;i++)
		{
			Point point;
			//在1/4到3/4区域内的正态分布点
			point.x=rng.uniform(image.cols/4,image.cols*3/4);
			point.y=rng.uniform(image.rows/4,image.rows*3/4);
			circle(image,point,2,Scalar::all(255),2);
			points.push_back(point);
		}

		Rect rect=boundingRect(points);
		vector<Point> hull{rect.tl(),Point(rect.x+rect.width,rect.y),rect.br(),Point(rect.x,rect.y+rect.height)};
		for(int i=0;i<4;i++)
		{
			line(image,hull[i],hull[(i+1)%4],Scalar::all(255),2);
		}

		namedWindow(W_CONVEX,WINDOW_NORMAL);
		imshow(W_CONVEX,image);

		//图像重新变成全黑的
		image=Scalar::all(0);

		if(waitKey()=='q') return 0;

	}

	return 0;
}

在这里插入图片描述

2.寻找最小包围矩形minAreaRect()

原型

RotateRect minAreaRect(InputArray points)

参数

points:Mat类或者是std::vector二维点集
返回一个包围点的RotatedRect

例子:

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define W_CONVEX "RESULT"

int main()
{
	Mat image=Mat::zeros(600,600,CV_8UC3);

	//初始化rng
	RNG& rng=theRNG();

	while(1)
	{
		char key;

		//获得一个3到103的数量
		int count=(unsigned)rng%100+3;
		vector<Point> points;

		for(int i=0;i<count;i++)
		{
			Point point;
			//在1/4到3/4区域内的正态分布点
			point.x=rng.uniform(image.cols/4,image.cols*3/4);
			point.y=rng.uniform(image.rows/4,image.rows*3/4);
			circle(image,point,2,Scalar::all(255),2);
			points.push_back(point);
		}

		RotatedRect rect=minAreaRect(points);
		Point2f hull[4];
		rect.points(hull);
		for(int i=0;i<4;i++)
		{
			line(image,hull[i],hull[(i+1)%4],Scalar::all(255),2);
		}

		namedWindow(W_CONVEX,WINDOW_NORMAL);
		imshow(W_CONVEX,image);

		//图像重新变成全黑的
		image=Scalar::all(0);

		if(waitKey()=='q') return 0;

	}

	return 0;
}

在这里插入图片描述

3.寻找最小包围圆形minEnclosingCircle()

原型

void minEnclosingCircle(
	InputArray points,
	Point2f& center,
	float& radius
);

参数

  • points:Mat类或者是std::vector二维点集
  • center:圆心位置
  • radius:圆的半径

例子:

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define W_CONVEX "RESULT"

int main()
{
	Mat image=Mat::zeros(600,600,CV_8UC3);

	//初始化rng
	RNG& rng=theRNG();

	while(1)
	{
		char key;

		//获得一个3到103的数量
		int count=(unsigned)rng%100+3;
		vector<Point> points;

		for(int i=0;i<count;i++)
		{
			Point point;
			//在1/4到3/4区域内的正态分布点
			point.x=rng.uniform(image.cols/4,image.cols*3/4);
			point.y=rng.uniform(image.rows/4,image.rows*3/4);
			circle(image,point,2,Scalar::all(255),2);
			points.push_back(point);
		}
		
		Point2f center;
		float radius;
		minEnclosingCircle(points,center,radius);
		circle(image,center,radius,Scalar::all(255),2);

		namedWindow(W_CONVEX,WINDOW_NORMAL);
		imshow(W_CONVEX,image);

		//图像重新变成全黑的
		image=Scalar::all(0);

		if(waitKey()=='q') return 0;

	}

	return 0;
}

在这里插入图片描述

4.用椭圆拟合二维点集fitEllipse()

原型

RotateRect fitEllipse(InputArray points)

注意:点集points内点的个数必须大于等于5个

参数

points:Mat类或者是std::vector二维点集

例子

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define W_CONVEX "RESULT"

int main()
{
	Mat image=Mat::zeros(600,600,CV_8UC3);

	//初始化rng
	RNG& rng=theRNG();

	while(1)
	{
		char key;

		//获得一个3到103的数量
		int count=(unsigned)rng%100+3;
		vector<Point> points;

		for(int i=0;i<count;i++)
		{
			Point point;
			//在1/4到3/4区域内的正态分布点
			point.x=rng.uniform(image.cols/4,image.cols*3/4);
			point.y=rng.uniform(image.rows/4,image.rows*3/4);
			circle(image,point,2,Scalar::all(255),2);
			points.push_back(point);
		}

		if(count<5) continue;

		RotatedRect fitRect=fitEllipse(points);
		
		ellipse(image,fitRect,Scalar::all(255),2);

		namedWindow(W_CONVEX,WINDOW_NORMAL);
		imshow(W_CONVEX,image);

		//图像重新变成全黑的
		image=Scalar::all(0);

		if(waitKey()=='q') return 0;

	}

	return 0;
}

在这里插入图片描述

5.逼近多边形曲线approxPolyDP()

原型

void approxPolyDP(
	InputArray curve,
	OutputArray approxCurve,
	double epsilon,
	bool closed
)

参数

  • points:Mat类或者是std::vector二维点集
  • approxCurve:多边形逼近的结果,类型和points一致
  • epsilon:逼近的精度
  • closed:真为封闭曲线(第一个和最后一个顶点相连),假为不封闭。

例子

五、其他

1.测量点是否在其中pointPolygonTest()

原型

double pointPolygonTest(
	InputArray contour, 
	Point2f pt, 
	bool measureDist
);

参数

  • contour:findContours()获得的轮廓
  • pt:点
  • measureDist:决定返回值的类型。
    • 当为true时,返回pt点距离轮廓中与其最近的点的距离。
    • 当为false时,返回+1、0或-1
  • 返回值:返回判断结果
    • 在其中inside:正值
    • 在边上edge:0值
    • 在外边:负值

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main()
{
	Mat src=imread("/home/volume/VSCode/imageSrc/cube.png",0);

	vector<vector<Point> > contours;
	findContours(src,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);

	cout<<pointPolygonTest(contours[0],Point2f(1,1),true)<<endl;
	//-196.471
	cout<<pointPolygonTest(contours[0],Point2f(1,1),false)<<endl;
	//-1
	
	cout<<pointPolygonTest(contours[0],contours[0][0],true)<<endl;
	//-0
	cout<<(pointPolygonTest(contours[0],contours[0][0],true)==0)<<endl;
	//1,看来-0也是等于0的。
	cout<<pointPolygonTest(contours[0],contours[0][0],false)<<endl;
	//0
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值