简体   繁体   中英

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.

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.

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".

  • 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

     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[[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:

在此处输入图像描述


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 :

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:
在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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