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

实现的基本思路是:

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

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

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

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

  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 coordinatescv::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 spacestd::vector<std::vector<InnerExploratorNode> > nodes; // 2-dimensional vector to easily find the neighborsint 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 areafor(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 timestd::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 spaceInnerExploratorNode 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 centerif (completeCellTest(inflated_rotated_image, current_node.center_, grid_spacing_as_int) == true){//如果是第一个元素,则为0,否则是前一个元素计数基础上加1current_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 visitedelse{current_node.leftCount = 0;++number_of_nodes;}current_row.push_back(current_node);}// insert the current row into gridnodes.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 mapstd::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 寻找图形最大内接矩形相关推荐

  1. opencv 最大内接矩形笔记

    python 最小外接矩形, 最小外接矩形的顶点坐标:cv2.boxPoints cnt = np.array([[data_0_x, data_0_y], [data_1_x, data_1_y], ...

  2. python莫比乌斯内接矩形_用莫比乌斯带巧解内接矩形问题:拓扑学的用处

    问题 对于任意的闭合环路,是否总能在其上找到四个点形成一个矩形? 该问题也被称为内接矩形问题,而内接正方形问题至今没有解答方案. 首先我们不再关注单个而是成对的点,并利用矩形的性质:对于平面上任意两对 ...

  3. 用莫比乌斯带巧解内接矩形问题:拓扑学的用处

    问题 对于任意的闭合环路,是否总能在其上找到四个点形成一个矩形? 该问题也被称为内接矩形问题,而内接正方形问题至今没有解答方案. 首先我们不再关注单个而是成对的点,并利用矩形的性质:对于平面上任意两对 ...

  4. OpenCV轮廓最大内接矩形(带角度)-计算与绘制(Python / C++源码)

    实现效果 OpenCV获取轮廓/Blob最大内接矩形(带角度) 实现源码 一.C++ OpenCV实现: #include "pch.h" #include <iostrea ...

  5. opencv实现轮廓的内接正矩形

    参考python-opencv 图像捕捉多个不规则轮廓,与轮廓内接区域(圆/矩形)思路-持续更新编辑中(会附上详细的思路解释和图片) - Lorzen - 博客园 前言 提示:利用中心延展算法的思想, ...

  6. 【千律】OpenCV基础:图像外接矩形、最小外接矩形、凸包、外接圆、拟合椭圆的绘制

    环境:Python3.8 和 OpenCV 内容:图像外接矩形.最小外接矩形.凸包.外接圆.拟合椭圆的绘制 import cv2 as cv import numpy as np import mat ...

  7. 获取轮廓、获取内接矩形

    对原图像,使用Imgproc.findContours获取轮廓. 对轮廓,使用Imgproc.minAreaRect获取轮廓的内接矩形(可能会有旋转角度). 对上述内接矩形使用boundingRect ...

  8. 如何利用OpenCV寻找轮廓的中心?

    简 介: 本文介绍了利用OpenCV和Python编程来计算形状轮廓的中心点.当然后面还会继续给出如何通过轮廓来分辨物体形状种类,以及对于各自的颜色进行标准. 关键词: OpenCV,contours ...

  9. 使用OpenCV检测图像中的矩形

    前言 1.OpenCV没有内置的矩形检测的函数,如果想检测矩形,要自己去实现. 2.我这里使用的OpenCV版本是3.30. 矩形检测 1.得到原始图像之后,代码处理的步骤是: (1)滤波增强边缘. ...

最新文章

  1. mysql存储过程调试学习总结
  2. R树 mysql_为什么MySQL使用B+树作为索引
  3. Redis | 001能做什么?
  4. 2019年 第10届 蓝桥杯 Java B组 决赛真题详解及小结
  5. 影之刃3服务器维护,影之刃3手游2021年3月11日维护公告_影之刃3手游2021年3月11日更新了什么_玩游戏网...
  6. 输入学生成绩,并按升序排列 Ascending.java
  7. LeetCode 1103. 分糖果 II
  8. 4014-基于邻接表的长度为k的简单路径的求解(C++,附思路)
  9. 利用PowerShell复制SQLServer账户的所有权限
  10. 有关圣诞节表白的c语言程序,关于圣诞节表白唯美的句子
  11. Exp2 后门原理与实践 20154328 常城
  12. 2021届校招求职计划、总结
  13. AIROBOT系统 之 私人存储 和 DLNA 智能电视云
  14. JavaScript 判断是否是数字 isFinite() Number.isFinite()
  15. 人民币大写的正确写法
  16. 链安团队漏洞分析连载(第一期)一一溢出漏洞
  17. 【烈日炎炎战后端】SpringMVC(0.5万字)
  18. 【QGIS插件安装】buildseg: QGIS plugin for building extraction
  19. python在日常的一些用处
  20. 全国计算机应用基础统考成绩查询,2020年12月网络教育统考成绩查询时间及入口...

热门文章

  1. JSP页面图片显示不了
  2. 异构网络中基于元图的推荐——FMG
  3. Python搭建tensorflow三层神经网络
  4. SpringBoot性能优化方案
  5. 2017_SIGIR_Item Silk Road: Recommending Items from Information Domains to Social Users
  6. 你给员工吃草,还指望他们有狼性?
  7. 常用API、static、数组复制、双色球练习与酒店管理系统
  8. jquery省市县三级联动
  9. 自律才是通往自由的唯一捷径
  10. 面向中国企业关系抽取的双向门控递归单元神经网络