opencv 最大内接矩形笔记

本文介绍使用Python和OpenCV实现图像中轮廓的最大内接矩形的方法,包括最小外接矩形、旋转矩形和最大内接矩形的计算过程,并提供C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

python 最小外接矩形,

轮廓矩形框:

旋转矩形和最小包围矩形求解

python 获取最大内接矩形方法2:

c++ opencv获取最大内接矩形


python 最小外接矩形,

最小外接矩形的顶点坐标:cv2.boxPoints

        cnt = np.array([[data_0_x, data_0_y], [data_1_x, data_1_y], [data_2_x, data_2_y], [data_3_x, data_3_y]])  # 必须是array数组的形式
        rect = cv2.minAreaRect(cnt)  # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)
        box = cv2.boxPoints(rect)  # 获取最小外接矩形的4个顶点坐标
        box = np.int0(box)
        cv2.drawContours(img, [box], 0, (255, 0, 0), 1)

轮廓矩形框:


cnt = np.array([[data_0_x, data_0_y], [data_1_x, data_1_y], [data_2_x, data_2_y], [data_3_x, data_3_y]])  # 必须是array数组的形式
ret=cv2.boundingRect(cnt)
x,y,w,h=ret

旋转矩形和最小包围矩形求解

在 OpenCV 中,寻找一个多边形的最大内接矩形并不直接支持。但是你可以使用旋转矩形(RotatedRect)和最小包围矩形(minAreaRect)的概念来解决这个问题。

基本的思路是这样的:

  1. 找到多边形的最小包围矩形(这个矩形可能是旋转的)。
  2. 旋转多边形,使得最小包围矩形与坐标轴对齐。
  3. 在旋转后的多边形中找到最大的内接矩形。

这是一个基本的 Python 和 OpenCV 代码实现:

import cv2
import numpy as np

def max_area_rect_in_poly(poly):
    # Find minimum area rectangle
    rect = cv2.minAreaRect(poly)
    box = cv2.boxPoints(rect)
    box = np.int0(box)

    # Rotate polygon to align minimum area rectangle with axis
    angle = rect[-1]
    if angle < -45:
        angle = (90 + angle)
    else:
        angle = -angle
    (h, w) = (poly.shape[0], poly.shape[1])
    center = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    poly = cv2.warpAffine(poly, M, (w, h))

    # Find maximum area rectangle in rotated polygon
    # Here you can use a brute force method to find the maximum area rectangle.
    # This can be a complex problem depending on the shape of your polygon.

    return max_rect

# Example usage:
poly = np.array([[10,10], [50,10], [50,30], [30,50], [10,30]], dtype=np.int32)
max_rect = max_area_rect_in_poly(poly)

python 获取最大内接矩形方法2:


原文链接:https://blog.csdn.net/weixin_43624833/article/details/129585389

import numpy as np
def get_max_inner_rectangles(matrix_np: np.ndarray, rectangle_bbox: list, area_value: int, result_list: list,
                             cur_area: float = float('inf')) -> list:
    """
    递归获取空间的多个内接矩形
    Args:
        matrix_np: 包含空间的底图
        rectangle_bbox: 空间的外接矩形
        area_value: 最小面积阈值
        result_list: 内接矩形列表
        cur_area: 当前矩形的面积
    Returns:
        result_list: 内接矩形列表
    """
    xmin, ymin, xmax, ymax = rectangle_bbox
    crop_img = matrix_np[ymin:ymax, xmin:xmax]  # 通过最大外接矩形,crop包含该空间的区域,优化速度
    matrix_list = crop_img.tolist()

    row = len(matrix_list)
    col = len(matrix_list[0])
    height = [0] * (col + 2)
    res = 0  # 记录矩形内像素值相加后的最大值
    bbox_rec = None  # 最大内接矩形bbox
    for i in range(row):
        stack = []  # 利用栈的特性获取最大矩形区域
        for j in range(col + 2):
            if 1 <= j <= col:
                if matrix_list[i][j - 1] == 255:
                    height[j] += 1
                else:
                    height[j] = 0
            # 精髓代码块 计算最大内接矩形 并计算最大值
            while stack and height[stack[-1]] > height[j]:
                cur = stack.pop()
                if res < (j - stack[-1] - 1) * height[cur]:
                    res = (j - stack[-1] - 1) * height[cur]
                    bbox_rec = [stack[-1], i - height[cur], j, i]
            stack.append(j)

    # 递归停止条件,1.最大内接矩形面积小于阈值;2. 没有最大内接矩形
    if cur_area < area_value or not bbox_rec:
        return result_list
    # 映射到原图中的位置
    src_min_x = xmin + bbox_rec[0]
    src_min_y = ymin + bbox_rec[1]
    src_max_x = xmin + bbox_rec[2]
    src_max_y = ymin + bbox_rec[3]
    bbox_src_position = [src_min_x, src_min_y, src_max_x, src_max_y]
    # 转成np格式,并将已经找到的最大内接矩形涂黑
    bbox_cnt = [[bbox_src_position[0], bbox_src_position[1]], 
                [bbox_src_position[2], bbox_src_position[1]], 
                [bbox_src_position[2], bbox_src_position[3]], 
                [bbox_src_position[0], bbox_src_position[3]]]
    contour_cur_np = np.array(bbox_cnt).reshape(-1, 1, 2)
    cv2.polylines(matrix_np, [contour_cur_np], 1, 0)
    cv2.fillPoly(matrix_np, [contour_cur_np], 0)
    cur_area =  (bbox_rec[2] - bbox_rec[0]) * (bbox_rec[3] - bbox_rec[1])
    if cur_area > area_value:
        result_list.append(bbox_src_position)
    # 递归获取剩下的内接矩形
    get_max_inner_rectangles(matrix_np, rectangle_bbox, area_value, result_list, cur_area)

    return result_list
x, y, w, h = cv2.boundingRect(cnt_final.reshape(-1,1,2))
cnt_bbox = [x, y,  x + w, y + h]
res_list = get_max_inner_rectangles(img, cnt_bbox, 100, [])
res_list = sorted(res_list, key=lambda _: (_[2] -_[0]) *(_[3] -_[1]), reverse=True)
res = res_list[0]
————————————————

一下内容转自:

python-opencv 图像捕捉多个不规则轮廓,与轮廓内接区域(圆/矩形)思路-持续更新编辑中(会附上详细的思路解释和图片) - Lorzen - 博客园

def drawInRectgle(img, cont, cX, cY, x_min, x_max, y_min, y_max):
            """绘制不规则最大内接正矩形"""
            # img 对应的是原图, 四个极值坐标对应的是最大外接矩形的四个顶点
            c = cont  # 单个轮廓
            # print(c)
            range_x, range_y = x_max - x_min, y_max - y_min   # 轮廓的X,Y的范围
            x1, x2, y1, y2 = cX, cX, cY, cY     # 中心扩散矩形的四个顶点x,y
            cnt_range, radio = 0, 0
            shape_flag = 1                      # 1:轮廓X轴方向比Y长;0:轮廓Y轴方向比X长
            if range_x > range_y:                     # 判断轮廓 X方向更长
                radio, shape_flag = int(range_x / range_y), 1
                range_x_left = cX - x_min
                range_x_right = x_max - cX
                if range_x_left >= range_x_right:   # 取轴更长范围作for循环
                    cnt_range = int(range_x_left)
                if range_x_left < range_x_right:
                    cnt_range = int(range_x_right)
            else:                                   # 判断轮廓 Y方向更长
                radio, shape_flag = int(range_y / range_x), 0
                range_y_top = cY - y_min
                range_y_bottom = y_max - cY
                if range_y_top >= range_y_bottom:   # 取轴更长范围作for循环
                    cnt_range = int(range_y_top)
                if range_y_top < range_y_bottom:
                    cnt_range = int(range_y_bottom)
            print("X radio Y: %d " % radio)
            print("---------new drawing range: %d-------------------------------------" % cnt_range)
            flag_x1, flag_x2, flag_y1, flag_y2 = False, False, False, False
            radio = 5       # 暂时设5,统一比例X:Y=5:1 因为发现某些会出现X:Y=4:1, 某些会出现X:Y=5:1
            if shape_flag == 1:
                radio_x = radio - 1
                radio_y = 1
            else:
                radio_x = 1
                radio_y = radio - 1
            for ix in range(1, cnt_range, 1):      # X方向延展,假设X:Y=3:1,那延展步进值X:Y=3:1
                # 第二象限延展
                if flag_y1 == False:
                    y1 -= 1 * radio_y       # 假设X:Y=1:1,轮廓XY方向长度接近,可理解为延展步进X:Y=1:1
                    p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False)
                    p_x2y1 = cv.pointPolygonTest(c, (x2, y1), False)
                    if p_x1y1 <= 0 or y1 <= y_min or p_x2y1 <= 0:  # 在轮廓外,只进行y运算,说明y超出范围
                        for count in range(0, radio_y - 1, 1):    # 最长返回步进延展
                            y1 += 1     # y超出, 步进返回
                            p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False)
                            if p_x1y1 <= 0 or y1 <= y_min or p_x2y1 <= 0:
                                pass
                            else:
                                break
                        # print("y1 = %d, P=%d" % (y1, p_x1y1))
                        flag_y1 = True

                if flag_x1 == False:
                    x1 -= 1 * radio_x
                    p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False)    # 满足第二象限的要求,像素都在轮廓内
                    p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False)    # 满足第三象限的要求,像素都在轮廓内
                    if p_x1y1 <= 0 or x1 <= x_min or p_x1y2 <= 0:       # 若X超出轮廓范围
                        # x1 += 1  # x超出, 返回原点
                        for count in range(0, radio_x-1, 1):       #
                            x1 += 1         # x超出, 步进返回
                            p_x1y1 = cv.pointPolygonTest(c, (x1, y1), False)  # 满足第二象限的要求,像素都在轮廓内
                            p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False)  # 满足第三象限的要求,像素都在轮廓内
                            if p_x1y1 <= 0 or x1 <= x_min or p_x1y2 <= 0:
                                pass
                            else:
                                break
                        # print("x1 = %d, P=%d" % (x1, p_x1y1))
                        flag_x1 = True              # X轴像左延展达到轮廓边界,标志=True
                # 第三象限延展
                if flag_y2 == False:
                    y2 += 1 * radio_y
                    p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False)
                    p_x2y2 = cv.pointPolygonTest(c, (x2, y2), False)
                    if p_x1y2 <= 0 or y2 >= y_max or p_x2y2 <= 0:  # 在轮廓外,只进行y运算,说明y超出范围
                        for count in range(0, radio_y - 1, 1):  # 最长返回步进延展
                            y2 -= 1     # y超出, 返回原点
                            p_x1y2 = cv.pointPolygonTest(c, (x1, y2), False)
                            if p_x1y2 <= 0 or y2 >= y_max or p_x2y2 <= 0:  # 在轮廓外,只进行y运算,说明y超出范围
                                pass
                            else:
                                break
                        # print("y2 = %d, P=%d" % (y2, p_x1y2))
                        flag_y2 = True              # Y轴像左延展达到轮廓边界,标志=True
                # 第一象限延展
                if flag_x2 == False:
                    x2 += 1 * radio_x
                    p_x2y1 = cv.pointPolygonTest(c, (x2, y1), False)    # 满足第一象限的要求,像素都在轮廓内
                    p_x2y2 = cv.pointPolygonTest(c, (x2, y2), False)    # 满足第四象限的要求,像素都在轮廓内
                    if p_x2y1 <= 0 or x2 >= x_max or p_x2y2 <= 0:
                        for count in range(0, radio_x - 1, 1):  # 最长返回步进延展
                            x2 -= 1     # x超出, 返回原点
                            p_x2y1 = cv.pointPolygonTest(c, (x2, y1), False)  # 满足第一象限的要求,像素都在轮廓内
                            p_x2y2 = cv.pointPolygonTest(c, (x2, y2), False)  # 满足第四象限的要求,像素都在轮廓内
                            if p_x2y1 <= 0 or x2 >= x_max or p_x2y2 <= 0:
                                pass
                            elif p_x2y2 > 0:
                                break
                        # print("x2 = %d, P=%d" % (x2, p_x2y1))
                        flag_x2 = True
                if flag_y1 and flag_x1 and flag_y2 and flag_x2:
                    print("(x1,y1)=(%d,%d)" % (x1, y1))
                    print("(x2,y2)=(%d,%d)" % (x2, y2))
                    break
            # cv.line(img, (x1,y1), (x2,y1), (255, 0, 0))
            cv.rectangle(img, (x1, y1), (x2, y2), (255, 255, 255), 1, 8)

            return x1, x2, y1, y2

c++ opencv获取最大内接矩形

OpenCVSharp 小练习 最大内接矩形_tfarcraw的博客-CSDN博客

​​​​​​opencv:求区域的内接矩形_cfqcfqcfqcfqcfq的博客-CSDN博客_opencv 内接矩形

#include<opencv2\opencv.hpp>
#include <iostream>
#include<vector>
 
using namespace cv;
using namespace std;
 
/**
* @brief expandEdge 扩展边界函数
* @param img:输入图像,单通道二值图,深度为8
* @param edge  边界数组,存放4条边界值
* @param edgeID 当前边界号
* @return 布尔值 确定当前边界是否可以扩展
*/
 
bool expandEdge(const Mat & img, int edge[], const int edgeID)
{
	//[1] --初始化参数
	int nc = img.cols;
	int nr = img.rows;
	switch (edgeID) {
	case 0:
		if (edge[0]>nr)
			return false;
		for (int i = edge[3]; i <= edge[1]; ++i)
		{
			if (img.at<uchar>(edge[0], i) == 255)//遇见255像素表明碰到边缘线
				return false;
		}
		edge[0]++;
		return true;
		break;
	case 1:
		if (edge[1]>nc)
			return false;
		for (int i = edge[2]; i <= edge[0]; ++i)
		{
			if (img.at<uchar>(i, edge[1]) == 255)//遇见255像素表明碰到边缘线
				return false;
		}
		edge[1]++;
		return true;
		break;
	case 2:
		if (edge[2]<0)
			return false;
		for (int i = edge[3]; i <= edge[1]; ++i)
		{
			if (img.at<uchar>(edge[2], i) == 255)//遇见255像素表明碰到边缘线
				return false;
		}
		edge[2]--;
		return true;
		break;
	case 3:
		if (edge[3]<0)
			return false;
		for (int i = edge[2]; i <= edge[0]; ++i)
		{
			if (img.at<uchar>(i, edge[3]) == 255)//遇见255像素表明碰到边缘线
				return false;
		}
		edge[3]--;
		return true;
		break;
	default:
		return false;
		break;
	}
 
}
 
/**
* @brief 求取连通区域内接矩
* @param img:输入图像,单通道二值图,深度为8
* @param center:最小外接矩的中心
* @return  最大内接矩形
* 基于中心扩展算法
*/
 
cv::Rect InSquare(Mat &img, const Point center)
{
	// --[1]参数检测
	if (img.empty() ||img.channels()>1|| img.depth()>8)
		return Rect();
	// --[2] 初始化变量
	int edge[4];
	edge[0] = center.y + 1;//top
	edge[1] = center.x + 1;//right
	edge[2] = center.y - 1;//bottom
	edge[3] = center.x - 1;//left
						   //[2]
						   // --[3]边界扩展(中心扩散法)
 
	bool EXPAND[4] = { 1,1,1,1 };//扩展标记位
	int n = 0;
	while (EXPAND[0] || EXPAND[1] || EXPAND[2] || EXPAND[3])
	{
		int edgeID = n % 4;
		EXPAND[edgeID] = expandEdge(img, edge, edgeID);
		n++;
	}
	//[3]
	//qDebug() << edge[0] << edge[1] << edge[2] << edge[3];
	Point tl = Point(edge[3], edge[0]);
	Point br = Point(edge[1], edge[2]);
	return Rect(tl, br);
}
 
 
 
 
int main()
{
 
	bool isExistence = false;
	float first_area = 0;
	/// 加载源图像
	Mat src;
	src = imread("cen.bmp", 1);
	//src = imread("C:\\Users\\Administrator\\Desktop\\测试图片\\xxx\\20190308152516.jpg",1);
	//src = imread("C:\\Users\\Administrator\\Desktop\\测试图片\\xx\\20190308151912.jpg",1);
	//src = imread("C:\\Users\\Administrator\\Desktop\\测试图像\\2\\BfImg17(x-247 y--91 z--666)-(492,280).jpg",1);
	cvtColor(src, src, CV_RGB2GRAY);
	threshold(src, src, 100, 255, THRESH_BINARY);
	Rect ccomp;
	Point center(src.cols / 2, src.rows / 2);
	//floodFill(src, center, Scalar(255, 255, 55), &ccomp, Scalar(20, 20, 20), Scalar(20, 20, 20));
	if (src.empty())
	{
		cout << "fali" << endl;
	}
	//resize(src, src, cv::Size(496, 460), cv::INTER_LINEAR);
	imshow("src", src);
	Rect rr = InSquare(src, center);
	rectangle(src, rr, Scalar(255), 1, 8);
	imshow("src2", src);
 
	waitKey(0);
	getchar();
	return 0;
}

原图和效果图:

### 回答1: OpenCV是一个开源计算机视觉库,提供了许多用于图像处理和计算机视觉的函数。其中一个函数是查找图像中最大矩形最大矩形是图像中最大的能够完全包含在其中的矩形,该矩形的边界不能穿过任何图像边缘或者其他对象的边界。在OpenCV中,可以使用函数minAreaRect来查找最大矩形。 该函数的参数是一个轮廓。轮廓是一组通过连续边界连在一起的点的集合。函数将返回一个矩形数据结构,其中包含了最大矩形的具体位置和大小。 要找到完全包含该轮廓的最大矩形,可以将所返回的矩形进行旋转。旋转的角度可以通过该矩形的角度(即旋转角度)来确定。在大多数情况下,用户只需要关心最大矩形的位置和大小即可。 总之,opencv中的最大矩形函数minAreaRect是一种用于查找图像中最大的能够完全包含在其中的矩形的方法,并且该函数能够返回该矩形的具体位置和大小,这对于计算机视觉与图像处理来说有着很高的应用价值。 ### 回答2: OpenCV是一款开源的计算机视觉库,提供了许多针对图像处理和计算机视觉问题的函数和算法。其中,最大矩形是一种常用的图像处理方法,可以用来提取图像中的目标区域。下面简单介绍一下OpenCV中的最大矩形算法。 最大矩形算法是基于轮廓图像的,因此在利用OpenCV实现时,需要先进行轮廓检测。找到轮廓之后,就可以使用cv::minAreaRect()函数来求解最小矩形轮廓。在最小矩形轮廓求解出来后,我们只需要将其旋转回原来的位置,就可以得到最大矩形。 具体实现方法如下: 首先,使用cv::findContours()函数来检测图像的轮廓,在检测之前需要进行图像二值化。着,使用cv::minAreaRect()函数来求解最小矩形轮廓。最后,使用cv::boxPoints()函数将最小矩形转换为矩形的四个顶点坐标,然后使用cv::RotatedRect()函数对矩形进行旋转操作,最终得到最大矩形。 需要注意的是,最大矩形并不是唯一的,可能会存在多个满足条件的矩形。因此,在实际应用中需要根据具体需求选择合适的矩形。另外,最大矩形算法对于含有弯曲结构的轮廓可能无法求解,需要进一步的处理。 综上所述,OpenCV提供了方便实用的最大矩形算法,可以帮助开发者更好地解决图像处理和计算机视觉问题。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值