Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crop Rectangle returned by minAreaRect OpenCV [Python]

minAreaRect in OpenCV returns a rotated rectangle. How do I crop this part of the image which is inside the rectangle?

boxPoints returns the co-ordinates of the corner points of the rotated rectangle so one can access the pixels by looping through the points inside the box, but is there a faster way to crop in Python?

EDIT

See code in my answer below.

like image 500
Abdul Fatir Avatar asked May 12 '16 05:05

Abdul Fatir


People also ask

How do I crop a rectangle in OpenCV?

To crop an image to a certain area with OpenCV, use NumPy slicing img[y:y+height, x:x+width] with the (x, y) starting point on the upper left and (x+width, y+height) ending point on the lower right. Those two points unambiguously define the rectangle to be cropped.

What does cv2 minAreaRect return?

OpenCV provides a function cv2. minAreaRect() for finding the minimum area rotated rectangle. This takes as input a 2D point set and returns a Box2D structure which contains the following details – (center(x, y), (width, height), angle of rotation).

How do you crop a rotated bounding box?

In the above code, we first find the rectangle enclosing the text area based on the four points we provide using the cv2. minAreaRect() method. Then in function crop_rect() , we calculate a rotation matrix and rotate the original image around the rectangle center to straighten the rotated rectangle.

How do you crop a rectangle image in Python?

crop() method is used to crop a rectangular portion of any image. Parameters: box – a 4-tuple defining the left, upper, right, and lower pixel coordinate. Return type: Image (Returns a rectangular region as (left, upper, right, lower)-tuple).


2 Answers

here a function that does this task:

import cv2
import numpy as np

def crop_minAreaRect(img, rect):

    # rotate img
    angle = rect[2]
    rows,cols = img.shape[0], img.shape[1]
    M = cv2.getRotationMatrix2D((cols/2,rows/2),angle,1)
    img_rot = cv2.warpAffine(img,M,(cols,rows))

    # rotate bounding box
    rect0 = (rect[0], rect[1], 0.0) 
    box = cv2.boxPoints(rect0)
    pts = np.int0(cv2.transform(np.array([box]), M))[0]    
    pts[pts < 0] = 0

    # crop
    img_crop = img_rot[pts[1][1]:pts[0][1], 
                       pts[1][0]:pts[2][0]]

    return img_crop

here an example usage

# generate image
img = np.zeros((1000, 1000), dtype=np.uint8)
img = cv2.line(img,(400,400),(511,511),1,120)
img = cv2.line(img,(300,300),(700,500),1,120)

# find contours / rectangle
_,contours,_ = cv2.findContours(img, 1, 1)
rect = cv2.minAreaRect(contours[0])

# crop
img_croped = crop_minAreaRect(img, rect)

# show
import matplotlib.pylab as plt
plt.figure()
plt.subplot(1,2,1)
plt.imshow(img)
plt.subplot(1,2,2)
plt.imshow(img_croped)
plt.show()

this is the output

original and croped image

like image 101
Oliver Wilken Avatar answered Oct 11 '22 19:10

Oliver Wilken


Here's the code to perform the above task. To speed up the process, instead of first rotating the entire image and cropping, part of the image which has the rotated rectangle is first cropped, then rotated, and cropped again to give the final result.

# Let cnt be the contour and img be the input

rect = cv2.minAreaRect(cnt)  
box = cv2.boxPoints(rect) 
box = np.int0(box)

W = rect[1][0]
H = rect[1][1]

Xs = [i[0] for i in box]
Ys = [i[1] for i in box]
x1 = min(Xs)
x2 = max(Xs)
y1 = min(Ys)
y2 = max(Ys)

angle = rect[2]
if angle < -45:
    angle += 90

# Center of rectangle in source image
center = ((x1+x2)/2,(y1+y2)/2)
# Size of the upright rectangle bounding the rotated rectangle
size = (x2-x1, y2-y1)
M = cv2.getRotationMatrix2D((size[0]/2, size[1]/2), angle, 1.0)
# Cropped upright rectangle
cropped = cv2.getRectSubPix(img, size, center)
cropped = cv2.warpAffine(cropped, M, size)
croppedW = H if H > W else W
croppedH = H if H < W else W
# Final cropped & rotated rectangle
croppedRotated = cv2.getRectSubPix(cropped, (int(croppedW),int(croppedH)), (size[0]/2, size[1]/2))
like image 26
Abdul Fatir Avatar answered Oct 11 '22 18:10

Abdul Fatir