OPENCV 寻找图形最大内接矩形

这篇具有很好参考价值的文章主要介绍了OPENCV 寻找图形最大内接矩形。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  轮廓的最大外接矩形,Opencv有提供的现成的算法,最大内接圆也有提供的算法。但是没有现成的内接矩形的算法。本文使用C++实现了取轮廓最大内接矩形的方式,供大家参考。

实现的基本思路是:

  1. 处理图片为灰度图
    其实实现的代码,直接就读入的是一张灰度图图片这一步省略了。当然如果实现起来,opencv也很容易实现。

  2. 坐标转换
    寻找轮廓的边缘,找到轮廓的主方向的角度。通过仿射转换,主方向作为x轴。

  3. 统计有效栅格。
    在转换完的图形中找到灰度值位255的区域,为了处理的效率,没有按照像素直接处理,而是将区域分为一个一个的小栅格区域。每个区域记录是否是有效值,同事记录该区域左侧有多少个同样有效的区域。当前直接处理像素也是一样的。本例只是提供一种思路,因为有些情况,噪点是希望被忽略掉的,那么小于一定大小的栅格就不会影响找出的最大外接矩形。

  4. 直方图方式统计最大面积
    经过上述处理后,得到了每行有效区域的信息,有行号,和每行有效区域的数据,就可以假设这是个直方图,用直方图的方式找最大面积。如下图:
    用数据结构栈就可以统计出局部最大峰值,很容易实现。
    opencv最大内接矩形,opencv,C++,opencv,计算机视觉,c++

  5. 找矩形顶点

通过上述的方式就能找到直方图的最大面积对应的四个区域的坐标,即为内接矩形的四个顶点。

  1. 将坐标再通过仿射转换,转为原图的坐标。

源码

void InnerRect::getInnerRect(const cv::Mat& image, std::vector<cv::Point2f>& Rect_points, const double grid_spacing_in_pixel)
{
	const int grid_spacing_as_int = std::floor(grid_spacing_in_pixel);
	const int half_grid_spacing_as_int = std::floor(grid_spacing_in_pixel*0.5);

	// *********************** I. Find the main directions of the map and rotate it in this manner. ***********************
	cv::Mat R;
	cv::Rect bbox;
	cv::Mat rotated_image;
	Rotator image_rotation;
	image_rotation.computeImageRotationMatrix(image, R, bbox);
	image_rotation.rotateImage(image, rotated_image, R, bbox);

	// compute min/max room coordinates
	cv::Point min_room(1000000, 1000000), max_room(0, 0);
	for (int v=0; v<rotated_image.rows; ++v)
	{
		for (int u=0; u<rotated_image.cols; ++u)
		{
			if (rotated_image.at<uchar>(v,u)==255)
			{
				min_room.x = std::min(min_room.x, u);
				min_room.y = std::min(min_room.y, v);
				max_room.x = std::max(max_room.x, u);
				max_room.y = std::max(max_room.y, v);
			}
		}
	}

	cv::Mat inflated_rotated_image;
	cv::erode(rotated_image, inflated_rotated_image, cv::Mat(), cv::Point(-1, -1), half_grid_spacing_as_int);

	// *********************** II. Find the nodes and their neighbors ***********************
	// get the nodes in the free space
	std::vector<std::vector<InnerExploratorNode> > nodes; // 2-dimensional vector to easily find the neighbors
	int number_of_nodes = 0;


	// todo: create grid in external class - it is the same in all approaches
	// todo: if first/last row or column in grid has accessible areas but center is inaccessible, create a node in the accessible area
	for(int y=min_room.y+half_grid_spacing_as_int; y<max_room.y; y+=grid_spacing_as_int)
	{
		// for the current row create a new set of neurons to span the network over time
		std::vector<InnerExploratorNode> current_row;
		for(int x=min_room.x+half_grid_spacing_as_int; x<max_room.x; x+=grid_spacing_as_int)
		{
			// create node if the current point is in the free space
			InnerExploratorNode current_node;
			current_node.center_ = cv::Point(x,y);
			//if(rotated_image.at<uchar>(y,x) == 255)				
			// could make sense to test all pixels of the cell, not only the center
			if (completeCellTest(inflated_rotated_image, current_node.center_, grid_spacing_as_int) == true)
			{
				//如果是第一个元素,则为0,否则是前一个元素计数基础上加1
				current_node.leftCount = (x == (min_room.x+half_grid_spacing_as_int) ? 0 : (current_row.back().leftCount +1));
				++number_of_nodes;
			}
			// add the obstacle nodes as already visited
			else
			{
				current_node.leftCount = 0;
				++number_of_nodes;
			}
			current_row.push_back(current_node);
		}

		// insert the current row into grid
		nodes.push_back(current_row);
	}
	std::cout << "found " << number_of_nodes <<  " nodes" << std::endl;

	if(nodes.empty())
	{
		return;
	}

	//采用柱状直方图统计方式,对每一列找最大面积
	int max_area = 0;
	int max_up = 0;
	int max_down = 0;
	int max_left = 0;
	int max_right = 0;
	int m = nodes.size();
	int n = nodes[0].size();
	for(int j = 0; j < n; j++)
	{
		std::vector<int> up(m, 0), down(m, 0);
		
		std::stack<int> stk;
		for(int i = 0; i < m; i++)
		{
			while(!stk.empty() && nodes[stk.top()][j].leftCount >= nodes[i][j].leftCount)
			{
				stk.pop();
			}
			up[i] = stk.empty() ? -1 : stk.top();
			stk.push(i);
		}
		stk = std::stack<int>();
		for (int i = m-1; i >= 0; i--){
			while(!stk.empty() && nodes[stk.top()][j].leftCount >= nodes[i][j].leftCount)
			{
				stk.pop();
			}
			down[i] = stk.empty() ? m : stk.top();
			stk.push(i);
		}


		for(int i = 0; i < m; i++)
		{
			int height = down[i] - up[i] -1;
			int area = height * nodes[i][j].leftCount;
			if(max_area < area)
			{
				max_area = area;
				max_up = up[i] + 1;
				max_down = down[i];
				max_left = j - nodes[i][j].leftCount + 1;
				max_right = j;
			}
		}
	}
	
	int min_x = min_room.x + max_left * grid_spacing_as_int + half_grid_spacing_as_int;
	int min_y = min_room.y + max_up * grid_spacing_as_int + half_grid_spacing_as_int;
	int max_x = min_room.x + max_right * grid_spacing_as_int + half_grid_spacing_as_int;
	int max_y = min_room.y + max_down * grid_spacing_as_int;



	//transform the calculated path back to the originally rotated map
	std::vector<cv::Point2f> fov_poses;
	std::vector<cv::Point2f> fov_coverage_path;

	fov_coverage_path.push_back(cv::Point2f(min_x, min_y));
	fov_coverage_path.push_back(cv::Point2f(max_x, min_y));
	fov_coverage_path.push_back(cv::Point2f(max_x, max_y));
	fov_coverage_path.push_back(cv::Point2f(min_x, max_y));
	fov_coverage_path.push_back(cv::Point2f(min_x, min_y));

	image_rotation.transformPathBackToOriginalRotation(fov_coverage_path, fov_poses, R);

	Rect_points.clear();
	Rect_points.insert(Rect_points.end(), fov_poses.begin(), fov_poses.end());

}

完整的源码上传到github上了,可以直接下载:

求最大内接矩形

实现效果:
原图:
opencv最大内接矩形,opencv,C++,opencv,计算机视觉,c++
实现找到的内接矩形效果:
opencv最大内接矩形,opencv,C++,opencv,计算机视觉,c++文章来源地址https://www.toymoban.com/news/detail-609563.html

到了这里,关于OPENCV 寻找图形最大内接矩形的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 计算点集的最小外接矩形——OpenCV的minAreaRect函数

    输入一系列二维点,返回其最小外接矩形。 根据函数原型,输入的数据可以是 vectorPoint 类型,包含1个以上的点; 返回值是 RotatedRect 类型,该类型的定义如下: 对于用户而言,最重要的是三个属性: center 、 size 、 angle 。其中 size 和 angle 需要着重介绍一下: RotatedRect的si

    2024年04月14日
    浏览(29)
  • opencv关于使用cvRotatedRect函数计算并画出矩形四个点的返回位置

    画矩形操作 Point center = Point((left.center.x + right.center.x) / 2, (left.center.y + right.center.y) / 2);                         RotatedRect rect = RotatedRect(center, Size(dis, meanheight), (left.angle +                                    right.angle) / 2);//计算装甲板的四个角点               

    2024年02月13日
    浏览(30)
  • 【OpenCV】OpenCV:计算机视觉的强大工具库

    摘要   OpenCV是一个广泛应用于计算机视觉领域的开源工具库,为开发者提供了丰富的图像处理和计算机视觉算法。本文将介绍OpenCV的功能和应用领域,并探讨它在实践中的重要性和前景。 📕作者简介: 热爱跑步的恒川 ,致力于C/C++、Java、Python等多编程语言,热爱跑步,

    2024年02月03日
    浏览(36)
  • OpenCV第 1 课 计算机视觉和 OpenCV 介绍

      我们人类可以通过眼睛看到五颜六色的世界,是因为人眼的视觉细胞中存在分别对红、绿、蓝敏感的 3 种细胞。其中的光感色素根据光线的不同进行不同比例的分解,从而让我们识别到各种颜色。   对人工智能而言,学会“ 看 ”也是非常关键的一步。那么机器人是如

    2024年01月24日
    浏览(36)
  • 【计算机视觉 · OpenCV】使用 OpenCV 调用手机摄像头

    Droidcam 是一款可以将手机变成网络摄像头的工具,我们可以利用 Droidcam 让 OpenCV 拥有调用手机摄像头的能力。 2.1 安装 DroidCam 在手机和电脑上分别安装 DroidCam 的客户端和服务端 下载地址:https://pan.baidu.com/s/1DrBn3P1Bx-SXa4d6oziifA?pwd=gr1o 提取码:gr1o 2.2 测试连接状态 手机和电脑需

    2024年02月09日
    浏览(33)
  • 计算机视觉:OpenCV相机标定

    针孔照相机模型是一种经典的相机模型,它将相机视为一个针孔,将场景中的点投影到成像平面上。在这个模型中,相机的 内参和外参 描述了相机的几何形状和相机的姿态。 相机的 内参矩阵 描述了相机的内部几何形状,包括相机的焦距、像素尺寸和像素坐标原点。相机的

    2024年01月19日
    浏览(49)
  • 计算机视觉(OpenCV+TensorFlow)

    本系列文章是OpenCV系列文章的第三篇,仍然跟随上篇内容主要聚焦于图像的一些操作 在通常情况下我们使用大小恒定的图像。但在某些情况下,我们需要使用不同分辨率的同幅图像,例如,在搜索图像中的某些内容比如脸部信息时,并不确定该内容在图像中占据的大小。这种

    2024年02月05日
    浏览(34)
  • 【计算机视觉】---OpenCV实现物体追踪

    OpenCV中的物体追踪算法基于视觉目标跟踪的原理。物体追踪的目标是在连续的图像序列中定位和跟踪特定物体的位置。 在物体追踪中,我们需要对目标对象进行表示。通常使用边界框(bounding box)来表示目标的位置和大小。边界框是一个矩形区域,由左上角的坐标(x,y)和

    2024年02月08日
    浏览(41)
  • 【opencv】计算机视觉:实时目标追踪

    目录 前言 解析 深入探究 前言 目标追踪技术对于民生、社会的发展以及国家军事能力的壮大都具有重要的意义。它不仅仅可以应用到体育赛事当中目标的捕捉,还可以应用到交通上,比如实时监测车辆是否超速等!对于国家的军事也具有一定的意义,比如说导弹识别目标等

    2024年02月05日
    浏览(35)
  • 开源计算机视觉库OpenCV详解

    目录 1、概述 2、OpenCV详细介绍 2.1、OpenCV的起源 2.2、OpenCV开发语言 2.3、OpenCV的应用领域 3、OpenCV模块划分 4、OpenCV源码文件结构 4.1、根目录介绍 4.2、常用模块介绍 4.3、CUDA加速模块 5、OpenCV配置以及Visual Studio使用OpenCV 6、关于Lena图片 7、OpenCV和OpenGL的区别 8、OpenCV与YOLO的区别

    2024年02月10日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包