• 外接矩形
2021-05-06 07:05:01

Matlab 中并没有发现最小外接矩形的代码，为了方便

下面提供最小外接矩形的代码：

注：这个函数是源于网上找到的代码的改进版，原版不能检测水平线或者垂直线

function [rectx,recty,area,perimeter] = minboundrect(x,y,metric)

% minboundrect: Compute the minimal bounding rectangle of points in the plane

% usage: [rectx,recty,area,perimeter] = minboundrect(x,y,metric)

%

% arguments: (input)

% x,y - vectors of points, describing points in the plane as

% (x,y) pairs. x and y must be the same lengths.

%

% metric - (OPTIONAL) - single letter character flag which

% denotes the use of minimal area or perimeter as the

% metric to be minimized. metric may be either 'a' or 'p',

% capitalization is ignored. Any other contraction of 'area'

% or 'perimeter' is also accepted.

%

% DEFAULT: 'a' ('area')

%

% arguments: (output)

% rectx,recty - 5x1 vectors of points that define the minimal

% bounding rectangle.

%

% area - (scalar) area of the minimal rect itself.

%

% perimeter - (scalar) perimeter of the minimal rect as found

%

%

% Note: For those individuals who would prefer the rect with minimum

% perimeter or area, careful testing convinces me that the minimum area

% rect was generally also the minimum perimeter rect on most problems

% (with one class of exceptions). This same testing appeared to verify my

% assumption that the minimum area rect must always contain at least

% one edge of the convex hull. The exception I refer to above is for

% problems when the convex hull is composed of only a few points,

% most likely exactly 3. Here one may see differences between the

% two metrics. My thanks to Roger Stafford for pointing out this

% class of counter-examples.

%

% Thanks are also due to Roger for pointing out a proof that the

% bounding rect must always contain an edge of the convex hull, in

% both the minimal perimeter and area cases.

%

%

%

%

% default for metric

if (nargin<3) || isempty(metric)

metric = 'a';

elseif ~ischar(metric)

error 'metric must be a character flag if it is supplied.'

else

% check for 'a' or 'p'

metric = lower(metric(:)');

ind = strmatch(metric,{'area','perimeter'});

if isempty(ind)

error 'metric does not match either ''area'' or ''perimeter'''

end

% just keep the first letter.

metric = metric(1);

end

% preprocess data

x=x(:);

y=y(:);

% not many error checks to worry about

n = length(x);

if n~=length(y)

error 'x and y must be the same sizes'

end

% if var(x)==0

% start out with the convex hull of the points to

% reduce the problem dramatically. Note that any

% points in the interior of the convex hull are

% never needed, so we drop them.

if n>3

%%%%%%%%%%%%%%%%%%%%%%%%%

if (var(x)== 0|| var(y)==0)

if var(x)== 0

x = [x-1;x(1); x+1 ];

y = [y ;y(1);y];

flag = 1;

else

y = [y-1;y(1); y+1 ];

x = [x ;x(1);x];

flag = 1;

end

else

flag = 0;

%%%%%%%%%%%%%%%%%%%%%%

edges = convhull(x,y); % 'Pp' will silence the warnings

end

% exclude those points inside the hull as not relevant

% also sorts the points into their convex hull as a

% closed polygon

%%%%%%%%%%%%%%%%%%%%

if flag == 0

%%%%%%%%%%%%%%%%%%%%

x = x(edges);

y = y(edges);

%%%%%%%%%%%%%%%%%%

end

%%%%%%%%%%%%%

% probably fewer points now, unless the points are fully convex

nedges = length(x) - 1;

elseif n>1

% n must be 2 or 3

nedges = n;

x(end+1) = x(1);

y(end+1) = y(1);

else

% n must be 0 or 1

nedges = n;

end

% now we must find the bounding rectangle of those

% that remain.

% special case small numbers of points. If we trip any

% of these cases, then we are done, so return.

switch nedges

case 0

% empty begets empty

rectx = [];

recty = [];

area = [];

perimeter = [];

return

case 1

% with one point, the rect is simple.

rectx = repmat(x,1,5);

recty = repmat(y,1,5);

area = 0;

perimeter = 0;

return

case 2

% only two points. also simple.

rectx = x([1 2 2 1 1]);

recty = y([1 2 2 1 1]);

area = 0;

perimeter = 2*sqrt(diff(x).^2 + diff(y).^2);

return

end

% 3 or more points.

% will need a 2x2 rotation matrix through an angle theta

Rmat = @(theta) [cos(theta) sin(theta);-sin(theta) cos(theta)];

% get the angle of each edge of the hull polygon.

ind = 1:(length(x)-1);

edgeangles = atan2(y(ind+1) - y(ind),x(ind+1) - x(ind));

% move the angle into the first quadrant.

edgeangles = unique(mod(edgeangles,pi/2));

% now just check each edge of the hull

nang = length(edgeangles);

area = inf;

perimeter = inf;

met = inf;

xy = [x,y];

for i = 1:nang

% rotate the data through -theta

rot = Rmat(-edgeangles(i));

xyr = xy*rot;

xymin = min(xyr,[],1);

xymax = max(xyr,[],1);

% The area is simple, as is the perimeter

A_i = prod(xymax - xymin);

P_i = 2*sum(xymax-xymin);

if metric=='a'

M_i = A_i;

else

M_i = P_i;

end

% new metric value for the current interval. Is it better?

if M_i

% keep this one

met = M_i;

area = A_i;

perimeter = P_i;

rect = [xymin;[xymax(1),xymin(2)];xymax;[xymin(1),xymax(2)];xymin];

rect = rect*rot';

rectx = rect(:,1);

recty = rect(:,2);

end

end

% get the final rect

% all done

end % mainline end

当然这段代码并没有获取到外接矩形的长和宽，下面我在写一个函数，就可以获得对应外接矩形的长和宽

function [ wid hei ] = minboxing( d_x , d_y )

%minboxing Summary of this function goes here

% Detailed explanation goes here

dd = [d_x, d_y];

dd1 = dd([4 1 2 3],:);

ds = sqrt(sum((dd-dd1).^2,2));

wid = min(ds(1:2));

hei = max(ds(1:2));

end

这里默认为较短的距离为宽，较长的距离为长。

调用代码如下：注(dataX, dataY为需要计算最小外接矩形的数据。)

[recty,rectx,area,perimeter] = minboundrect(dataX, dataY);

[wei hei] = minboxing(rectx(1:end-1),recty(1:end-1));

更多相关内容
• 最小外接矩形，计算偏转角，旋转至水平，根据最小的旋转角进行旋转，顺时针或者逆时针
• 包含多个区域的最小外接矩形''' image = cv2.imread('./label.png') B, G, R = cv2.split(image) ret, thresh = cv2.threshold(G, 128, 255, cv2.THRESH_BINARY) print(thresh.shape) # 单通道复制为三通道 ...代替...
• 在图像裁剪操作中，opencv和pillow两个库都具有相应的函数，但是这两个库中的函数仅仅能对与图片平行的矩形进行裁剪操作，如果想要对目标的最小外接矩形进行裁剪该如何操作呢？如下所示： 具体处理该问题的思路如下...
• 前两篇博文分别介绍了图像的边缘检测和轮廓检测，本文接着介绍图像的轮廓检测和轮廓外接矩形： 一、代码部分： // extract_contours.cpp : 定义控制台应用程序的入口点。 // #include stdafx.h #include #include ...
• Opencv中求点集的最小外结矩使用方法minAreaRect，求点集的最小外接圆使用方法minEnclosingCircle。 minAreaRect方法原型： RotatedRect minAreaRect( InputArray points ); 输入参数points是所要求最小外结矩的...
• 利用opencv找图像中形状的最小外接矩形，进而可获得最小外接矩形的信息等
• 资源中包含了两个m文件。...minboundrect.m用于绘制运动目标的最小外接矩形框，可任意设置最小外接矩形框的角度。 本人做的是视频中运动车辆的检测，读者可自行更换检测算法以及参数调整以匹配不同的运动场景。
• 主要介绍了python opencv minAreaRect 生成最小外接矩形的方法，小编觉得挺不错的，现在分享给大家，也给大家做个参考。一起跟随小编过来看看吧
• 1、概述 经常用到轮廓查找和多边形拟合等opencv操作，因此记录以备后续使用。本文代码中的阈值条件对图片没有实际意义，仅仅是为了测试。 原图为： 2、测试代码： import cv2 import numpy as np ...
• min_rect = cv2.minAreaRect(coords)//由点集获取最小矩形（包含中心坐标点、宽和高、偏转角度） print("min_rec =",min_rect) box = cv2.boxPoints(min_rect)//获取最小矩形的4个顶点坐标。 但是通过一下这个绘制...
• 该代码可用于求取一个多边形的最小外接矩形
• 本文实例为大家分享了Opencv实现最小外接矩形和圆的具体代码，供大家参考，具体内容如下 步骤：将一幅图像先转灰度，再canny边缘检测得到二值化边缘图像，再寻找轮廓，轮廓是由一系列点构成的，要想获得轮廓的最小...
• 参考网页上的历程，完善了软件功能，实现了最小外接矩形求解。在QT上测试通过，输入随意的不等数量的点，运行算法，获取最小矩形的边的所有参数。
• 凸包 蛮力 最小面积 最小外接矩形 文件选择 随机生成 凸包点位 然后求解
• 使用opencv画出图形的最小外接矩形与最小外接圆，首先求出图形的轮廓，设有滚动条可以选择最佳阈值，然后画出图形的最小外接圆与最小外接矩形，算法的效果很好！
• 求多个目标的最小外接矩形，有说明，matlab版
• 多边形最小外接矩形算法 程鹏飞 题目 给出求一个多边形最小外接矩形的算法并证明求得的是最小外接矩形. 最小外接矩形英文简称为SMBR(smallest minimum bounding rectangle,它和MBR(minimum bounding rectangle)不...
• 简单多边形的最小外接矩形算法，适用于玻璃排样等。
• 生成最小外接矩形： cnt = np.array([[x1,y1],[x2,y2],[x3,y3],[x4,y4]]) # 必须是array数组的形式 rect = cv2.minAreaRect(cnt) # 得到最小外接矩形的（中心(x,y), (宽,高), 旋转角度） box = cv2.cv.BoxPoints...

目录

opencv生成最小外接矩形：

最小外接矩形修正版：

### opencv生成最小外接矩形：

cnt = np.array([[x1,y1],[x2,y2],[x3,y3],[x4,y4]]) # 必须是array数组的形式

rect = cv2.minAreaRect(cnt) # 得到最小外接矩形的（中心(x,y), (宽,高), 旋转角度）
box = cv2.cv.BoxPoints(rect) # cv2.boxPoints(rect) for OpenCV 3.x 获取最小外接矩形的4个顶点
box = np.int0(box)



RotatedRect该类表示平面上的旋转矩形，有三个属性：

1. 矩形中心点(质心)
2. 边长(长和宽)
3. 旋转角度

旋转角度angle的范围为[-90,0)，当矩形水平或竖直时均返回-90，请看下图：

一、组成angel的最小外接矩形的边的选取问题。

angel的形成与选取的最小外接矩形的边有关，在这里我们只给出最终结论，有兴趣的同志，可以自己去验证一下，距离坐标原点最近的最小外接矩形的边，作为angel的一条边或者其延长线，而另一条边为X轴，两条线最终形成一个夹角。如图所示

————————————————
版权声明：本文为CSDN博主「WPeak」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/qq_39430765/article/details/99431709

### 最小外接矩形修正版：

GitHub - root12321/Rotation-Detect-yolov5_poly

def cvminAreaRect2longsideformat(x_c, y_c, width, height, theta):
'''
trans minAreaRect(x_c, y_c, width, height, θ) to longside format(x_c, y_c, longside, shortside, θ)
两者区别为:
当opencv表示法中width为最长边时（包括正方形的情况），则两种表示方法一致
当opencv表示法中width不为最长边 ，则最长边表示法的角度要在opencv的Θ基础上-90度
@param x_c: center_x
@param y_c: center_y
@param width: x轴逆时针旋转碰到的第一条边
@param height: 与width不同的边
@param theta: x轴逆时针旋转与width的夹角，由于原点位于图像的左上角，逆时针旋转角度为负 [-90, 0)
@return:
x_c: center_x
y_c: center_y
longside: 最长边
shortside: 最短边
theta_longside: 最长边和x轴逆时针旋转的夹角，逆时针方向角度为负 [-180, 0)
'''
'''
意外情况:(此时要将它们恢复符合规则的opencv形式：wh交换，Θ置为-90)
竖直box：box_width < box_height  θ=0
水平box：box_width > box_height  θ=0
'''
# print("theta",theta)
theta=int(theta)
if theta == 0:
theta = -90
buffer_width = width
width = height
height = buffer_width

if theta > 0:
if theta != 90:  # Θ=90说明wh中有为0的元素，即gt信息不完整，无需提示异常，直接删除
print('θ计算出现异常，当前数据为：%.16f, %.16f, %.16f, %.16f, %.1f;超出opencv表示法的范围：[-90,0)' % (
x_c, y_c, width, height, theta))
return False

if theta < -90:
print(
'θ计算出现异常，当前数据为：%.16f, %.16f, %.16f, %.16f, %.1f;超出opencv表示法的范围：[-90,0)' % (x_c, y_c, width, height, theta))
return False

if width != max(width, height):  # 若width不是最长边
longside = height
shortside = width
theta_longside = theta - 90
else:  # 若width是最长边(包括正方形的情况)
longside = width
shortside = height
theta_longside = theta

if longside < shortside:
print('旋转框转换表示形式后出现问题：最长边小于短边;[%.16f, %.16f, %.16f, %.16f, %.1f]' % (
x_c, y_c, longside, shortside, theta_longside))
return False
if (theta_longside < -180 or theta_longside >= 0):
print('旋转框转换表示形式时出现问题:θ超出长边表示法的范围：[-180,0);[%.16f, %.16f, %.16f, %.16f, %.1f]' % (
x_c, y_c, longside, shortside, theta_longside))
return False

return x_c, y_c, longside, shortside, theta_longside
def longsideformat2cvminAreaRect(x_c, y_c, longside, shortside, theta_longside):
'''
trans longside format(x_c, y_c, longside, shortside, θ) to minAreaRect(x_c, y_c, width, height, θ)
两者区别为:
当opencv表示法中width为最长边时（包括正方形的情况），则两种表示方法一致
当opencv表示法中width不为最长边 ，则最长边表示法的角度要在opencv的Θ基础上-90度
@param x_c: center_x
@param y_c: center_y
@param longside: 最长边
@param shortside: 最短边
@param theta_longside: 最长边和x轴逆时针旋转的夹角，逆时针方向角度为负 [-180, 0)
@return: ((x_c, y_c),(width, height),Θ)
x_c: center_x
y_c: center_y
width: x轴逆时针旋转碰到的第一条边最长边
height: 与width不同的边
theta: x轴逆时针旋转与width的夹角，由于原点位于图像的左上角，逆时针旋转角度为负 [-90, 0)
'''
theta_longside=int(theta_longside)
if (theta_longside >= -180 and theta_longside < -90):  # width is not the longest side
width = shortside
height = longside
theta = theta_longside + 90
else:
width = longside
height = shortside
theta = theta_longside

if theta < -90 or theta >= 0:
print('当前θ=%.1f，超出opencv的θ定义范围[-90, 0)' % theta)
return False

return ((x_c, y_c), (width, height), theta)

def xyxy2xywhn_new(x, w=640, h=640, clip=False, eps=0.0):
# Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] normalized where xy1=top-left, xy2=bottom-right
if clip:
clip_coords(x, (h - eps, w - eps))  # warning: inplace clip
y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)

codinate_new=[]
for i in y:
codinate=[]
point=np.array([(i[1],i[2]),(i[3],i[4]),(i[5],i[6]),(i[7],i[8])])
rect = cv2.minAreaRect(point)
c_x = rect[0][0]
c_y = rect[0][1]
w_label = rect[1][0]
h_label = rect[1][1]
theta = rect[-1]  # Range for angle is [-90，0)
if(w==0 or h==0 ):
continue
trans_data = cvminAreaRect2longsideformat(c_x, c_y, w_label, h_label, theta)

if not trans_data:
continue
else:
c_x, c_y, longside, shortside, theta_longside = trans_data
theta_label = int(theta_longside + 180.5)  # range int[0,180] 四舍五入
if theta_label == 180:  # range int[0,179]
theta_label = 179
if theta_label < 0 or theta_label > 179:
# print('id problems,问题出现在该图片中:%s' % (i, img_fullname))
print('出问题的longside形式数据:[%.16f, %.16f, %.16f, %.16f, %.1f]' % (
c_x, c_y, longside, shortside, theta_longside))
continue
codinate.append(i[0])
codinate.append(c_x/w)
codinate.append(c_y/h)
codinate.append(longside/w)
codinate.append(shortside/h)
codinate.append(theta_label)
codinate_new.append(codinate)

codinate_new=np.array(codinate_new)
return codinate_new

展开全文
• EmguCV基础视频教程---第25讲(轮廓特征属性及应用(三)---最小外接矩形).pptx
• 通过目标的对角点，可以框出目标的最小外接矩形
• 最大最小外接矩形

import cv2
import numpy as np

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#二值化，注意有两个返回值，阈值和结果
thresh, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
contours, hierachy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

rect = cv2.minAreaRect(contours[1])
#cv2.drawContours(img, contours, 1, (0, 0, 255), 2)这一步可以画轮廓
#rect是一个Rotated Rect旋转的矩形，矩形的起始坐标xy，长宽，旋转角度
#注意box给的是小数，但坐标必须是整数，要转化一下
box = cv2.boxPoints(rect)

box = np.round(box).astype('int64')
cv2.drawContours(img, [newbox], 0, (0, 0, 255), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

#最大
import cv2
import numpy as np

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#二值化，注意有两个返回值，阈值和结果
thresh, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
contours, hierachy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

rect = cv2.minAreaRect(contours[1])
#cv2.drawContours(img, contours, 1, (0, 0, 255), 2)这一步可以画轮廓
#rect是一个Rotated Rect旋转的矩形，矩形的起始坐标xy，长宽，旋转角度
#注意box给的是小数，但坐标必须是整数，要转化一下
box = cv2.boxPoints(rect)

box = np.round(box).astype('int64')
cv2.drawContours(img, [box], 0, (0, 0, 255), 2)

#最大返回四个（xy（（wh）,此处操作为最大
x, y, w, h = cv2.boundingRect(contours[1])

cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()`

展开全文
• 应用OpenCV开源库，通过对图像的分析，确定图像中电子器件重心的像素位置
• matlab计算目标最小外接矩形,主要利用minboundrect函数。
• DOS界面，找图像中最大的轮廓、画外接矩形，计算矩形度

...