欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Opencv——查找并绘制凸包、凸包与轮廓的关系

程序员文章站 2023-12-25 19:36:21
...

定义

给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型。
理解物体形状或轮廓的一 种比较有用的方法便是计算一个物体的凸包,然后计算其凸缺陷(convexity defects)。
Opencv——查找并绘制凸包、凸包与轮廓的关系

检测凸包

opencv自带函数:convexHull()

参数解释:
Opencv——查找并绘制凸包、凸包与轮廓的关系

示例1:检测随机点群的凸包(只有一个凸包)

代码以及注释:

#include <opencv2/opencv.hpp>
#include <iostream>
#include "windows.h"
#include <stdio.h>
#include <time.h>

using namespace cv;
using namespace std;

//===========================凸包检测基础====================
//先随机生成3~103个坐标值随机的彩色点,然后利用convexHull,对链接起来的图形求凸包
int main()
{
	Mat image(600, 600, CV_8UC3);
	//RNG& rng = theRNG();		//返回一个当前线程的随机数生成器		RNG类可以产生多种类型的随机数,故使用时需要指定是哪种类型的
	RNG rng((unsigned)time(NULL));		//这样每次重新运行会产生不一样的随机数
	while (1)
	{
		//参数初始化
		char key;
		int count = (unsigned)rng % 100 + 3;	//随机生成点的数量
		vector<Point> points;		//点值

		//随机生成点坐标
		for (int i = 0;i < count;i++)
		{
			Point point;
			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);			//将此时生成的点数据送入	points数组的最后一个
		}
		//检测凸包(这里认为凸包只有一个)
		vector<int> hull;		//存储一个凸包的边的一维数组	
		convexHull(Mat(points),hull,true);
		//输入二维点集,输出找到的凸包
		//绘制出随机颜色的点
		image = Scalar::all(0);		//背景
		for (int i = 0;i < count;i++)
		{
			circle(image,points[i],3,Scalar(rng.uniform(0,255), rng.uniform(0, 255), rng.uniform(0, 255)),FILLED,LINE_AA);
		}
		//准备参数
		int hullcount = (int)hull.size();		//凸包的边数(因为只有一个凸包,而凸包是由边构成的序列,所以返回序列长度,应该返回的是边的个数)
		Point point0 = points[hull[hullcount - 1]];		//连接凸包边的坐标点		最后一条边的坐标点

		//绘制凸包的边
		for (int i = 0;i < hullcount;i++)
		{
			Point point = points[hull[i]];		//points[hull[i]]表示构成凸包边的某点(因为凸包是一个点集合最外面的点连接起来的区域)
			line(image, point0, point, Scalar(255, 255, 255), 2, LINE_AA);
			point0 = point;
		}
		//显示效果图
		imshow("凸包检测示例",image);

		//按下ESC程序退出
		//key = (char)waitKey();
		//if (key == 27) break;
		waitKey(1000);		//每秒显示一次
	}
	return 0;
}

演示效果:
Opencv——查找并绘制凸包、凸包与轮廓的关系

示例2:动态检测并绘制轮廓和凸包(一个轮廓对应一个凸包)

//===========================动态检测绘制图形的轮廓和凸包====================

//=================全局变量声明=================
Mat g_srcImage;
Mat g_grayImage;
int g_nThresh = 50;
int g_nThresh_max = 255;
RNG g_rng(12345);
Mat srcImage_copy = g_srcImage.clone();
Mat g_thresholdMat_output;
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;

//=============全局函数声明===============
void on_ThreshChange(int,void*);
int main()
{
	// Read image 读取图像
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);		//字体为绿色
	//载入原图
	g_srcImage = imread("D:\\opencv_picture_test\\lena.jpg",1);
	//Mat srcImage = imread("D:\\opencv_picture_test\\形态学操作\\孔洞.png", 0);	//读取灰度图
	//转换成灰度并且模糊化降噪
	cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
	blur(g_grayImage, g_grayImage, Size(3, 3));
	//创建窗口
	namedWindow("原始图窗口", WINDOW_AUTOSIZE);
	imshow("原始图窗口", g_srcImage);
	//创建滑动条并初始化
	createTrackbar("阈值", "原始图窗口", &g_nThresh,g_nThresh_max, on_ThreshChange);
	on_ThreshChange(0,0);
	waitKey(0);
	return 0;
}
void on_ThreshChange(int, void*)
{
	//用Canny算子检测边缘
	Canny(g_grayImage, g_thresholdMat_output, g_nThresh, g_nThresh * 2, 3);
	//寻找轮廓.
	findContours(g_thresholdMat_output, g_vContours, g_vHierarchy,
		RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	//遍历每个轮廓,寻找其凸包
	vector<vector<Point> > hull( g_vContours.size());		//轮廓、凸包、点,构成三维数组	凸包的数组的大小等于轮廓的大小
	for (unsigned int i = 0;i<g_vContours.size();i++)
	{
		convexHull(Mat (g_vContours[i]), hull[i],false);		//在轮廓数组中寻找凸包,存入对应的hull中
	}
	//绘出轮廓及其凸包
	Mat drawing = Mat::zeros(g_thresholdMat_output.size(), CV_8UC3);
	for (int i = 0; i < g_vContours.size(); i++)
	{
		Scalar color = Scalar(g_rng.uniform(0, 255),
			g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值
		//绘制轮廓
		drawContours(drawing, g_vContours, i, color, 1, 8, g_vHierarchy,
			0, Point());
		//绘制凸包
		drawContours(drawing, hull, i, color, 1, 8, g_vHierarchy,
			0, Point());
	}
	//显示效果图
	imshow("效果图",drawing);
}

演示效果:
1、仅绘制凸包:
Opencv——查找并绘制凸包、凸包与轮廓的关系
2、仅绘制轮廓:
Opencv——查找并绘制凸包、凸包与轮廓的关系
3、既绘制轮廓也绘制凸包:
Opencv——查找并绘制凸包、凸包与轮廓的关系
更加凸显出轮廓与凸包的关系。
总结:
学到的凸包知识点:检测并绘制凸包;轮廓、凸包、凸包连接点的结构关系。
学到的c++语法知识点:随机数生成器RNG的用法;vector的push_back()操作。

参考链接:
C++RNG类与毛星云寻找凸包例程的理解
C++ push方法与push_back方法

相关标签: opencv基本操作

上一篇:

下一篇: