简体   繁体   English

如何在 openCV 中“拉伸”出从 minAreaRect function 给出的边界框?

[英]How to "stretch" out a bounding box given from minAreaRect function in openCV?

I wish to run a line detector between two known points on an image but firstly I need to widen the area around the line so my line detector has more area to work with.我希望在图像上的两个已知点之间运行线检测器,但首先我需要加宽线周围的区域,以便我的线检测器有更多的工作区域。 The main issue it stretch the area around line with respect to the line slope.主要问题是相对于线斜率拉伸线周围的区域。 For instance: white line generated form two points with black bounding box .例如:白线由带有黑色边界框的两点生成

I tried manualy manipulating the box array:我尝试手动操作框数组:

input_to_min_area = np.array([[660, 888], [653, 540]]) # this works instead of contour as an input to minAreaRect

rect = cv.minAreaRect(input_to_min_area)
box = cv.boxPoints(rect)
box[[0, 3], 0] += 20
box[[1, 2], 0] -= 20
box = np.int0(box)

cv.drawContours(self.images[0], [box], 0, (0, 255, 255), 2)

But that doesn't work for any line slope.但这不适用于任何线斜率。 From vertical to this angle everything is fine, but for the horizontal lines doesn't work.从垂直到这个角度一切都很好,但对于水平线不起作用。

What would be a simpler solution that works for any line slope?适用于任何线斜率的更简单的解决方案是什么?

A minAreaRect() gives you a center point, the size of the rectangle, and an angle. minAreaRect()为您提供中心点、矩形的大小和角度。

You could just add to the shorter side length of the rectangle.你可以只增加矩形的边长度。 Then you have a description of a "wider rectangle".然后你有一个“更宽的矩形”的描述。 You can then do with it whatever you want, such as call boxPoints() on it.然后你可以随心所欲地处理它,比如在它上面调用boxPoints()

padding = 42

rect = cv.minAreaRect(input_to_min_area)

(center, (w,h), angle) = rect # take it apart

if w < h: # we don't know which side is longer, add to shorter side
    w += padding
else:
    h += padding

rect = (center, (w,h), angle) # rebuild

A box around your two endpoints, widened:两个端点周围的框加宽:

在此处输入图像描述

We may add the padding in the axis that is perpendicular to the angle of the " minAreaRect".我们可以在垂直于“minAreaRect”的角度的轴上添加填充。

  • Get the angle, and convert to radians获取角度,并转换为弧度

     angle = np.deg2rad(rect[2]) # Angle of minAreaRect
  • Padding in each direction is perpendicular to the angle of minAreaRect每个方向的填充垂直于 minAreaRect 的角度

     pad_x = 20*np.sin(angle) pad_y = 20*np.cos(angle)
  • Add the padding in both axes:在两个轴上添加填充:
    Assume the order of the point in box is sorted according to the angle of rect (I don't know if it's always true - sorting the points may be required).假设 box 中点的顺序是根据rect的角度排序的(我不知道它是否总是正确的 - 可能需要对点进行排序)。

     box[[0, 3], 0] -= pad_x box[[1, 2], 0] += pad_x box[[0, 3], 1] += pad_y box[[1, 2], 1] -= pad_y box = np.int0(box)

Code sample:代码示例:

import cv2
import numpy as np

img = cv2.imread('sketch.png')

#input_to_min_area = np.array([[584, 147], [587, 502]]) # this works instead of contour as an input to minAreaRect
#input_to_min_area = np.array([[109, 515], [585, 144]]) # this works instead of contour as an input to minAreaRect
input_to_min_area = np.array([[80, 103], [590, 502]]) # this works instead of contour as an input to minAreaRect

rect = cv2.minAreaRect(input_to_min_area)
box = cv2.boxPoints(rect)

angle = np.deg2rad(rect[2])  # Angle of minAreaRect

# Padding in each direction is perpendicular to the angle of minAreaRect
pad_x = 20*np.sin(angle)
pad_y = 20*np.cos(angle)

box[[0, 3], 0] -= pad_x
box[[1, 2], 0] += pad_x
box[[0, 3], 1] += pad_y
box[[1, 2], 1] -= pad_y
box = np.int0(box)

cv2.drawContours(img, [box], 0, (0, 255, 255), 2)

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

Sample output:样本 output:

在此处输入图像描述


We may also want to expand the box in the parallel direction.我们可能还想在平行方向上扩展盒子。
I am still not sure about the signs...我仍然不确定这些迹象...

In this case it's simpler to update input_to_min_area :在这种情况下,更新input_to_min_area更简单:

import cv2
import numpy as np

img = cv2.imread('sketch.png')

#input_to_min_area = np.array([[584, 147], [587, 502]]) # this works instead of contour as an input to minAreaRect
#input_to_min_area = np.array([[109, 515], [585, 144]]) # this works instead of contour as an input to minAreaRect
input_to_min_area = np.array([[80, 103], [590, 502]]) # this works instead of contour as an input to minAreaRect

rect = cv2.minAreaRect(input_to_min_area)

angle = np.deg2rad(rect[2])  # Angle of minAreaRect
pad_x = int(round(20*np.cos(angle)))
pad_y = int(round(20*np.sin(angle)))
tmp_to_min_area = np.array([[input_to_min_area[0, 0]+pad_x, input_to_min_area[0, 1]+pad_y], [input_to_min_area[1, 0]-pad_x, input_to_min_area[1, 1]-pad_y]])
rect = cv2.minAreaRect(tmp_to_min_area)

box = cv2.boxPoints(rect)

angle = np.deg2rad(rect[2])  # Angle of minAreaRect

# Padding in each direction is perpendicular to the angle of minAreaRect
pad_x = 20*np.sin(angle)
pad_y = 20*np.cos(angle)

box[[0, 3], 0] -= pad_x
box[[1, 2], 0] += pad_x
box[[0, 3], 1] += pad_y
box[[1, 2], 1] -= pad_y

box = np.int0(box)

cv2.drawContours(img, [box], 0, (0, 255, 255), 2)

cv2.line(img, (tmp_to_min_area[0, 0], tmp_to_min_area[0, 1]), (tmp_to_min_area[1, 0], tmp_to_min_area[1, 1]), (255, 0, 0), 2)

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

Output: Output:
在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM