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

有时需要对已有的图像进行处理,使其更清晰或更规则,轮廓检测可以达到这个目的。先介绍几个相关函数:
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);
	
}

在这里插入图片描述

  • 0
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我明白了您的问题。首先,需要使用图像处理库(如OpenCV)进行图像轮廓查找绘制。以下是Python代码示例: ```python import cv2 # 读取图像 img = cv2.imread("image.jpg") # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, thresh = cv2.threshold(gray, 127, 255, 0) # 查找轮廓 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 绘制轮廓 cv2.drawContours(img, contours, -1, (0,255,0), 3) # 显示图像 cv2.imshow("Image", img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 接下来,可以使用以下方法计算物体的面积: 1. `cv2.contourArea()`函数:该函数可以直接计算轮廓的面积。示例代码如下: ```python # 计算轮廓面积 area = cv2.contourArea(contours[0]) # 显示面积 print("Area:", area) ``` 2. `cv2.moments()`函数:该函数可以计算轮廓的几何矩。通过几何矩可以计算出物体的面积、重心等信息。示例代码如下: ```python # 计算几何矩 M = cv2.moments(contours[0]) # 计算面积 area = M['m00'] # 显示面积 print("Area:", area) ``` 3. `cv2.fitEllipse()`函数:该函数可以拟合出轮廓的椭圆形状。从椭圆的长短轴长度可以计算出物体的面积。示例代码如下: ```python # 拟合椭圆 ellipse = cv2.fitEllipse(contours[0]) # 计算面积 a = ellipse[1][0] / 2 b = ellipse[1][1] / 2 area = 3.1415926 * a * b # 显示面积 print("Area:", area) ``` 以上就是三种计算物体面积的方法。接下来,可以使用以下方法拟合出物体的轮廓: 1. `cv2.approxPolyDP()`函数:该函数可以将轮廓拟合成多边形。示例代码如下: ```python # 拟合多边形 epsilon = 0.01 * cv2.arcLength(contours[0], True) approx = cv2.approxPolyDP(contours[0], epsilon, True) # 绘制多边形 cv2.drawContours(img, [approx], -1, (0,0,255), 3) # 显示图像 cv2.imshow("Image", img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 2. `cv2.minAreaRect()`函数:该函数可以拟合出轮廓的最小外接矩形。示例代码如下: ```python # 拟合最小外接矩形 rect = cv2.minAreaRect(contours[0]) # 将矩形转换为四个顶点坐标 box = cv2.boxPoints(rect) box = np.int0(box) # 绘制矩形 cv2.drawContours(img, [box], 0, (0,0,255), 3) # 显示图像 cv2.imshow("Image", img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 3. `cv2.fitLine()`函数:该函数可以拟合出轮廓的一条直线。示例代码如下: ```python # 拟合直线 rows,cols = img.shape[:2] [vx,vy,x,y] = cv2.fitLine(contours[0], cv2.DIST_L2,0,0.01,0.01) lefty = int((-x*vy/vx) + y) righty = int(((cols-x)*vy/vx)+y) cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2) # 显示图像 cv2.imshow("Image", img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上就是三种拟合物体轮廓的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值