简体   繁体   English

OpenCV Python:绘制 minAreaRect(未实现 RotatedRect)

[英]OpenCV Python: Draw minAreaRect ( RotatedRect not implemented)

Are there any helper methods to draw a rotated rectangle that is returned by cv2.minAreaRect() presumably as ((x1,y1),(x2,y2),angle) ?是否有任何辅助方法可以绘制由cv2.minAreaRect()返回的旋转矩形,大概为((x1,y1),(x2,y2),angle) cv2.rectangle() does not support an angle. cv2.rectangle()不支持角度。 And since the tuple returned is not of the "RotatedRect" class (because it seems to not be implemented in the Python bindings) there is no points() method, as shown in the C++ tutorial "Creating Bounding rotated boxes and ellipses for contours¶" .并且由于返回的元组不属于“RotatedRect”类(因为它似乎没有在 Python 绑定中实现),因此没有points()方法,如 C++ 教程“为轮廓创建边界旋转框和椭圆”中所示¶ ”

How could a rotated rectangle be drawn from lines - rotate about the center point or the first point given?如何从直线绘制旋转的矩形 - 围绕中心点或给定的第一个点旋转?

rect = cv2.minAreaRect(cnt)
box = cv2.cv.BoxPoints(rect) # cv2.boxPoints(rect) for OpenCV 3.x
box = np.int0(box)
cv2.drawContours(im,[box],0,(0,0,255),2)

should do the trick.应该做的伎俩。

sources:来源:

1) http://opencvpython.blogspot.in/2012/06/contours-2-brotherhood.html 1) http://opencvpython.blogspot.in/2012/06/contours-2-brotherhood.html

2) Python OpenCV Box2D 2) Python OpenCV Box2D

I know this was asked long ago, but I would like to share a different approach as the one proposed by the accepted answer, maybe this could be helpful for someone else (actually this has been done before in C++, but it seems python still lacks of RotatedRect class).我知道很久以前就有人问过这个问题,但是我想分享一种与接受的答案提出的方法不同的方法,也许这对其他人有帮助(实际上这已经在 C++ 中完成了,但似乎 python 仍然缺乏RotatedRect类)。

The idea is to define a rotated rectangle from an angle, a size (W and H) and an initial point.这个想法是从一个角度、一个大小(W 和 H)和一个初始点定义一个旋转的矩形。 This initial point is the relative top-left corner (the top-left corner of the same size rectangle with no rotation angle).这个初始点是相对的左上角(没有旋转角度的相同大小矩形的左上角)。 From here, the four vertices can be obtained, which allows us to draw the rotated rectangle with four lines.从这里,可以获得四个顶点,这允许我们用四条线绘制旋转的矩形。

class RRect:
  def __init__(self, p0, s, ang):
    self.p0 = (int(p0[0]),int(p0[1]))
    (self.W, self.H) = s
    self.ang = ang
    self.p1,self.p2,self.p3 = self.get_verts(p0,s[0],s[1],ang)
    self.verts = [self.p0,self.p1,self.p2,self.p3]

  def get_verts(self, p0, W, H, ang):
    sin = numpy.sin(ang/180*3.14159)
    cos = numpy.cos(ang/180*3.14159)
    P1 = (int(self.H*sin)+p0[0],int(self.H*cos)+p0[1])
    P2 = (int(self.W*cos)+P1[0],int(-self.W*sin)+P1[1])
    P3 = (int(self.W*cos)+p0[0],int(-self.W*sin)+p0[1])
    return [P1,P2,P3]

  def draw(self, image):
    print(self.verts)
    for i in range(len(self.verts)-1):
      cv2.line(image, (self.verts[i][0], self.verts[i][1]), (self.verts[i+1][0],self.verts[i+1][1]), (0,255,0), 2)
    cv2.line(image, (self.verts[3][0], self.verts[3][1]), (self.verts[0][0], self.verts[0][1]), (0,255,0), 2)

(W, H) = (30,60)
ang = 35 #degrees
P0 = (50,50)
rr = RRect(P0,(W,H),ang)
rr.draw(image)
cv2.imshow("Text Detection", image)
cv2.waitKey(200)

I guess, a similar approach can be used to define the rotated rectangle in terms of its center instead of its relative top-left initial point, but I haven't tried it yet.我想,可以使用类似的方法根据其中心而不是其相对左上角的初始点来定义旋转矩形,但我还没有尝试过。

Here's a concrete example to draw the rotated rectangle.这是绘制旋转矩形的具体示例。 The idea is to obtain a binary image with Otsu's threshold then find contours using cv2.findContours .这个想法是用Otsu 的阈值获得一个二值图像,然后使用cv2.findContours找到轮廓。 We can obtain the rotated rectangle using cv2.minAreaRect and the four corner vertices using cv2.boxPoints .我们可以得到使用旋转矩形cv2.minAreaRect和使用四个角落的顶点cv2.boxPoints To draw the rectangle we can use cv2.drawContours or cv2.polylines .要绘制矩形,我们可以使用cv2.drawContourscv2.polylines


Input -> Output输入->输出

Code代码

import cv2
import numpy as np

# Load image, convert to grayscale, Otsu's threshold for binary image
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Find contours, find rotated rectangle, obtain four verticies, and draw 
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
rect = cv2.minAreaRect(cnts[0])
box = np.int0(cv2.boxPoints(rect))
cv2.drawContours(image, [box], 0, (36,255,12), 3) # OR
# cv2.polylines(image, [box], True, (36,255,12), 3)

cv2.imshow('image', image)
cv2.waitKey()

In extension to Tobias Hermann's answer: in case you don't have a contour, but a rotated rectangle defined by its center point, dimensions and angle: Tobias Hermann 的回答的延伸:如果您没有轮廓,而是由其中心点、尺寸和角度定义的旋转矩形:

import cv2
import numpy as np

# given your rotated rectangle is defined by variables used below

rect = ((center_x, center_y), (dim_x, dim_y), angle)
box = cv2.cv.BoxPoints(rect) # cv2.boxPoints(rect) for OpenCV 3.x
box = np.int0(box)
cv2.drawContours(im,[box],0,(0,0,255),2)

Based on @ smajtks 's answer I define the rotated rectangle in terms of its center instead of its relative top-left initial point.根据@ smajtks的回答,我根据其中心而不是相对左上角的初始点来定义旋转的矩形。 Here is the code:这是代码:

class RRect_center:
  def __init__(self, p0, s, ang):
    (self.W, self.H) = s # rectangle width and height
    self.d = math.sqrt(self.W**2 + self.H**2)/2.0 # distance from center to vertices    
    self.c = (int(p0[0]+self.W/2.0),int(p0[1]+self.H/2.0)) # center point coordinates
    self.ang = ang # rotation angle
    self.alpha = math.radians(self.ang) # rotation angle in radians
    self.beta = math.atan2(self.H, self.W) # angle between d and horizontal axis
    # Center Rotated vertices in image frame
    self.P0 = (int(self.c[0] - self.d * math.cos(self.beta - self.alpha)), int(self.c[1] - self.d * math.sin(self.beta-self.alpha))) 
    self.P1 = (int(self.c[0] - self.d * math.cos(self.beta + self.alpha)), int(self.c[1] + self.d * math.sin(self.beta+self.alpha))) 
    self.P2 = (int(self.c[0] + self.d * math.cos(self.beta - self.alpha)), int(self.c[1] + self.d * math.sin(self.beta-self.alpha))) 
    self.P3 = (int(self.c[0] + self.d * math.cos(self.beta + self.alpha)), int(self.c[1] - self.d * math.sin(self.beta+self.alpha))) 

    self.verts = [self.P0,self.P1,self.P2,self.P3]

  def draw(self, image):
    # print(self.verts)
    for i in range(len(self.verts)-1):
      cv2.line(image, (self.verts[i][0], self.verts[i][1]), (self.verts[i+1][0],self.verts[i+1][1]), (0,255,0), 2)
    cv2.line(image, (self.verts[3][0], self.verts[3][1]), (self.verts[0][0], self.verts[0][1]), (0,255,0), 2)

(W, H) = (30,60)
ang = 35 #degrees
P0 = (50,50)
rr = RRect_center(P0,(W,H),ang)
rr.draw(image)
cv2.imshow("Text Detection", image)
cv2.waitKey(200

Here, the rectangle is rotated around its center, not from the initial point P0.在这里,矩形围绕其中心旋转,而不是从初始点 P0。

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

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