轮廓查找、绘制以及轮廓长度计算

有时需要对已有的图像进行处理,使其更清晰或更规则,轮廓检测可以达到这个目的。先介绍几个相关函数:
1.findContours函数

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

第一个参数:image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像
第二个参数:contours,定义为“vector<vector> contours”,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。
第三个参数:hierarchy,表示层数,定义为“vector hierarchy”, 定义了一个“向量内每一个元素包含了4个int型变量”的向量。
第四个参数:int型的mode,定义轮廓的检索模式:
取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
取值二:CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关 系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓, 所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到
取值三:CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围 内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层
取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
第五个参数:int型的method,定义轮廓的近似方法:
取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内
取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留

2.drawContours函数

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() )

其中第一个参数image表示目标图像,

第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,

第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,

第四个参数color为轮廓的颜色,

第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,

第六个参数lineType为线型,

第七个参数为轮廓结构信息,

第八个参数为maxLevel

3.approxPolyDP函数
它是用来进行多边形逼近,可以将不规则的图形逼近成规则图形,方便处理

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

InputArray curve:一般是由图像的轮廓点组成的点集

OutputArray approxCurve:表示输出的多边形点集

double epsilon:主要表示输出的精度,就是另个轮廓点之间最大距离数

bool closed:表示输出的多边形是否封闭,封闭可用true表示

下面举个例子来说明这些函数的用途,以便理解:

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>  //opencv申明
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>
#include "highgui.h"

using namespace std;
using namespace cv;
int dis,dis1,dis2,dis3,dis4,dis5,dis6;

int length(Point a,Point b)//两点间距离求边长
{
	int d = (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
	dis = sqrt(d);
	return dis;
	 
}
int main()
{
	int sum = 0;
	Mat t_image,f_image,src;
	vector<Vec4i> hierarchy;
	vector<vector<Point>> contours;
	Mat image = imread("D:\\program\\51.png",0);//读入模板图
	Mat dstImg(image.size(), CV_8UC3, Scalar::all(0));//纯黑图像

    int u1 = image.rows;//阈值化处理
	int u2 = image.cols;
	for (int i = 0; i < image.rows; i++)
	{
		for (int j = 0; j < image.cols; j++)
		{
			
	        sum = sum + image.at<uchar>(i, j);
		}
	}
	int u = u1*u2;
	int average = (int)sum/u*2;
	threshold(image, src, average, 255, CV_THRESH_BINARY); 
	Canny(src,t_image,50,50);
	imshow("阈值分割图",t_image);
	waitKey(0);


	findContours(t_image, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));//得到原图像轮廓点集
	drawContours(dstImg, contours,-1, Scalar(0, 255, 255), 2, 8);//根据点集画出图像轮廓
	imshow("轮廓图",dstImg);
	waitKey(0);
	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_poly, i, Scalar(0, 255, 255), 2, 8);  //绘制逼近图形
		/*for(int j = 0;j<contours_poly[i].size;j++)
		{
			Point pta = contours_poly[i][j];
			Point pta = contours_poly[i][j+1];
		}*/
		    Point pta = contours_poly[i][0];//提出逼近图像点集计算边长
		    Point ptb = contours_poly[i][1];
		    Point ptc = contours_poly[i][2];
		    Point ptd = contours_poly[i][3];
			//Point pte = contours_poly[i][4];
			//Point ptf = contours_poly[i][5];
			dis1 = length(pta,ptb);
	        dis2 = length(ptb,ptc);
	        dis3 = length(ptc,ptd);
	        dis4 = length(ptd,pta);
			
    }
	cout<<"各边长度为:"<<dis1<<"、"<<dis2<<"、"<<dis3<<"、"<<dis4<<endl;
	imshow("轮廓图",dstImg);
	waitKey(0);
	
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43491924/article/details/87901244