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()
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.