当前位置: 首页 > news >正文

open cv凸包

什么是凸包(Convex Hull)?

:得到的结果是一个凸出的形状,可以理解为一个凸多边形
:包围图像中的所有东西

未封闭的凸包叫做凸壳
在这里插入图片描述

在一个多边形边缘或者内部任意两个点的连线都包含在多边形边界或者内部
凸包跟多边形逼近很像,只不过它是物体最外层的”凸”多边形:集合A内连接任意两个点的直线都在A的内部,则称集合A是凸形的
在这里插入图片描述

当然,这个是对于二维平面,我们通过二维平面来理解凸包,那我们现在给出在多维平面(向量空间)中的定义:

在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。X的凸包可以用X内所有点(X1,…Xn)的凸组合来构造.


正式定义:包含点集合S中所有点的最小凸多边形称为凸包。
检测算法-Graham扫描法和Jarvis步进法

Graham扫描法:
首先选择Y方向最低的点作为起始点p0
从p0开始极坐标扫描,依次添加p1…pn(排序顺序是根据极坐标的角度大小,逆时针方向)
对每个点pi来说,如果添加pi点到凸包中导致一个左转向(逆时针方向)则添加该点到凸包
反之如果导致一个右转向(顺时针方向)则从凸包中删除该点
在这里插入图片描述

在这里插入图片描述

OpenCV中已经实现了凸包发现算法和API提供我们使用

API说明cv::convexHull
(
InputArray points–输入候选点,来自findContours(首先要寻找轮廓并获得轮廓点集合数组contourPoints)
OutputArray hull–凸包,构成凸包的点
bool clockwise–default true,顺时针方向
bool returnPoints–true表示返回点个数,如果第二个参数是vector则自动忽略
)


1.首先把图像转换为灰度图像cvtColor
2.将图像转屏幕坐标系为二值图像threshold
3.通过发现轮廓得到候选点findContours
4.凸包API调用convexHull
5.绘制显示drawContours,凸包也是一种特殊的轮廓(最小化的 满足一定条件的轮廓)

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;

Mat src, dst,srcGray;
void ConvexHULL(int, void*);

int thre = 100;
int threMax = 255;

int main()
{

	src = imread("D:/实验台/机器视觉/测试图片/白人女.jpg");
	if (src.empty())//如果src这个数据库属性为空
	{
		cout << "无法打开" << endl;
		return -1;
	}
	imshow("原图", src);

	//进行图像的预处理(灰度化和模糊去噪)
	cvtColor(src,srcGray,CV_BGR2GRAY);
	blur(srcGray,srcGray,Size(3,3),Point(-1,-1),BORDER_DEFAULT);
	//BORDER_DEFAULT用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT
	//这里进行边缘的去除 主要是为了舍弃位于边界的点 防止边界上的某个点影响凸包结果 
	imshow("灰度化", srcGray);
	namedWindow("凸包", CV_WINDOW_AUTOSIZE);
	createTrackbar("阈值调节","凸包",&thre,threMax,ConvexHULL);
	ConvexHULL(0, 0);
	waitKey(0);
	return 0;
}

void ConvexHULL(int, void*)
{
	Mat bin;//bin=BINARY(二值化)

	//使用阈值二值化或其他边源处理算子对图像进行二值化处理和简单的边缘提取
	threshold(srcGray,bin,thre,threMax,THRESH_BINARY);//准备进行凸包检测最好是背景和被检测区域二值化明显的图像 
	//Canny(srcGray, bin, thre, thre*2, 3, false);//不能使用边缘提取处理过的图像进行凸包检测 效果很差 无法达到一个凸包包裹全部检测区域的目的
	imshow("二值化", bin);

	//凸包可以理解为不是那么太标准的轮廓 所以也需要二值图像的轮廓信息 也需要轮廓的二维点集合和层次结构信息
	vector<vector<Point>>contourPoints;//双重动态向量Point类型容器 存储轮廓二维点集合
	vector<Vec4i>hierarchy;//4维int类型动态向量数组 存储轮廓的层次结构信息

	findContours(bin,contourPoints,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0));
	//轮廓发现
	//输入的图像(8位单通道灰度或二值化图像)
	//输出的轮廓二维点集合 
	//输出的轮廓层次结构信息
	//轮廓的检索模式(RETR_TREE 提取所有轮廓 重建网状轮廓结构)
	//轮廓近似方法(CHAIN_APPROX_SIMPLE 压缩水平,垂直,对角线方向元素 仅仅保存轮廓的拐点,存入contours向量内)
	//轮廓的偏移量(Point(0,0) 默认不进行偏移)


	vector<vector<Point>>convexs(contourPoints.size());//存储被压入栈的凸包点二维集合,容量初始化为轮廓点的数量
	vector<Vec4i>empty(0);//设置层次结构信息为空 或者直接在绘制凸包直接把层次结构参数改为Mat()空数组 

	for(size_t i=0;i<contourPoints.size();i++)//凸包查找次数为轮廓点的数量
	{
		//凸包的算法原理详解https://blog.csdn.net/u013377068/article/details/80095620?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159257753219724846444125%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=159257753219724846444125&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduend~default-6-80095620.pc_v1_rank_blog_v1&utm_term=%E5%87%B8%E5%8C%85
		convexHull(contourPoints[i], convexs[i],true,false);
		//凸包
		//  (1)InputArray类型的points,输入二维点集,存储在std::vector或Mat中
		//  (2)OutputArray类型的hull,输出凸包.它可以是索引的整数向量,也可以是点的向量
		//(3)bool类型的clockwise,方向标志.如果为true,则输出凸包将顺时针方向 如果为false是逆时针方向的(假定坐标系的X轴指向右侧,Y轴指向上方)***此案例中修改为true和false返回的坐标信息会变化但凸包绘制效果不变***
		//(4)bool类型的returnPoints,操作标志.对于矩阵,当标志为true时,函数返回凸壳点.如果为false,返回凸壳点的索引 ***此案例中不论修改为true还是false返回的结果不变n***

		//***cv.convexHull() 有个可选参数returnPoints,默认是True,代表返回角点的x / y坐标;如果为False的话,表示返回轮廓中是凸包角点的索引
	}//对每一组轮廓的全部轮廓点计算其凸包,留下符合凸包的点存入convexs堆栈中,其余从栈中出栈舍弃


	RNG rng(12345);
	dst = Mat::zeros(srcGray.size(), CV_8UC3);//在纯黑色背景中绘制
	//src.copyTo(dst);//在原图中绘制
	//不能直接在src里绘制 需要先把src的数据转移给不会在程序循环里被别的处理程序处理(src会在main函数中被反复灰度化和模糊)的图片dst
	for (size_t k = 0; k < contourPoints.size(); k++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		Scalar color2 = Scalar(0, 255, 0);
		drawContours(dst,contourPoints,k,color,2,LINE_8,hierarchy,0,Point(0,0));
		drawContours(dst, convexs, k, color2, 2, LINE_8, empty, 0, Point(0, 0));//empty==Mat();
		//轮廓绘制
		//绘制目标图像
		//输入的轮廓信息数组
		//轮廓的索引编号
		//轮廓颜色
		//线条宽度 -1为填充轮廓
		//线条类型
		//可选的层次结构信息 凸包不需要层次结构信息
		//绘制轮廓的最高级别 默认为0
		//轮廓绘制偏移量坐标
	}
	imshow("凸包", dst);
	
	/*
	for (size_t i = 0; i < convexs.size(); i++)//
	{
		cout <<"第"<<i+1 <<"个凸包轮廓点集合"<<endl;
		{
			cout << convexs[i];//
		}
		cout << endl;
	}*/
}

在这里插入图片描述
应用场景
在这里插入图片描述
在这里插入图片描述

关于凸包概念和凸包查找算法 Graham扫描法
https://blog.csdn.net/shuiyixin/article/details/104625013?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159249288619195264558210%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159249288619195264558210&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v1~rank_blog_v1-1-104625013.pc_v1_rank_blog_v1&utm_term=%E5%87%B8%E5%8C%85

相关文章:

  • open cv轮廓周围绘制圆形和矩形
  • open cv图形矩
  • Python标准库的学习准备
  • open cv点多边形测试
  • 将redhat的yum换成centos的yum
  • open cv基于距离变换与分水岭的图像分割
  • poj 1661 Help Jimmy (动态规划)
  • 呕心沥血!open cv4.1.2添加contrib4.1.2扩展模块
  • java基础----垃圾回收器如何工作
  • open cvSURF特征检测
  • php条件判断
  • open cvSIFT特征点检测
  • open cvHOG特征检测
  • todo格式定义
  • open cv积分图计算
  • 自己简单写的 事件订阅机制
  • [译]Python中的类属性与实例属性的区别
  • 2017 前端面试准备 - 收藏集 - 掘金
  • download使用浅析
  • isset在php5.6-和php7.0+的一些差异
  • LeetCode算法系列_0891_子序列宽度之和
  • MQ框架的比较
  • mysql 数据库四种事务隔离级别
  • node入门
  • Spark学习笔记之相关记录
  • 对象管理器(defineProperty)学习笔记
  • 服务器从安装到部署全过程(二)
  • 基于axios的vue插件,让http请求更简单
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 区块链技术特点之去中心化特性
  • 实现菜单下拉伸展折叠效果demo
  • 异步
  • ​​​​​​​​​​​​​​Γ函数
  • !!java web学习笔记(一到五)
  • # Apache SeaTunnel 究竟是什么?
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (04)odoo视图操作
  • (2)(2.10) LTM telemetry
  • (2015)JS ES6 必知的十个 特性
  • (31)对象的克隆
  • (5)STL算法之复制
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (搬运以学习)flask 上下文的实现
  • (接口封装)
  • (小白学Java)Java简介和基本配置
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • .Family_物联网
  • .NET MVC第三章、三种传值方式
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET 依赖注入和配置系统
  • .net对接阿里云CSB服务
  • .NET文档生成工具ADB使用图文教程