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.rectangle() does not support an angle.
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¶”.

How could a rotated rectangle be drawn from lines – rotate about the center point or the first point given?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

rect = cv2.minAreaRect(cnt)
box = cv2.cv.BoxPoints(rect) # cv2.boxPoints(rect) for OpenCV 3.x
box = np.int0(box)
cv2.drawContours(im,<div class="su-box su-box-style-default" id="" style="border-color:#000000;border-radius:3px"><div class="su-box-title" style="background-color:#333333;color:#FFFFFF;border-top-left-radius:1px;border-top-right-radius:1px">This is box title</div><div class="su-box-content su-u-clearfix su-u-trim" style="border-bottom-left-radius:1px;border-bottom-right-radius:1px"></div></div>,0,(0,0,255),2)

should do the trick.

sources:

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

2) Python OpenCV Box2D

Method 2

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(). We can obtain the rotated rectangle using cv2.minAreaRect() and the four corner vertices using cv2.boxPoints(). To draw the rectangle we can use cv2.drawContours() or cv2.polylines().


Input -> Output

2q1sj

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, <div class="su-box su-box-style-default" id="" style="border-color:#000000;border-radius:3px"><div class="su-box-title" style="background-color:#333333;color:#FFFFFF;border-top-left-radius:1px;border-top-right-radius:1px">This is box title</div><div class="su-box-content su-u-clearfix su-u-trim" style="border-bottom-left-radius:1px;border-bottom-right-radius:1px"></div></div>, 0, (36,255,12), 3) # OR
# cv2.polylines(image, <div class="su-box su-box-style-default" id="" style="border-color:#000000;border-radius:3px"><div class="su-box-title" style="background-color:#333333;color:#FFFFFF;border-top-left-radius:1px;border-top-right-radius:1px">This is box title</div><div class="su-box-content su-u-clearfix su-u-trim" style="border-bottom-left-radius:1px;border-bottom-right-radius:1px"></div></div>, True, (36,255,12), 3)

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

Method 3

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

The idea is to define a rotated rectangle from an angle, a size (W and H) and an initial point. 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.

Method 4

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:

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,
This is box title
,0,(0,0,255),2)

Method 5

Based on @smajtks‘s answer I define the rotated rectangle in terms of its center instead of its relative top-left initial point. 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.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x