简体   繁体   中英

Opencv: how to draw a rotated bounding box in python

I am currently doing a project on painting recognition using opencv-python. Right now I am able to detect most of the paintings decently however the bounding boxes are rectangles that include a lot of background. This is because the cv2.boundingRect() function finds the bounding rectangle with a perpendicular projection (afaik). However I want to find the best bounding box without detecting any background.

The main part of my code:

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

hue, saturation, value = cv2.split(hsv)
blurred_sat = cv2.GaussianBlur(saturation, (5, 5), 0)
edges = cv2.Canny(blurred_sat, 45, 100)

kernel = np.ones((3, 3), np.uint8)
dilate = cv2.dilate(edges, kernel, iterations=6)
erode = cv2.erode(dilate, kernel, iterations=2)
contours, hierarchy = cv2.findContours(erode, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]

# cv2.drawContours(frame, contours, -1, (255, 255, 0), 3)
for contour in contours:
    area = cv2.contourArea(contour)
    if area >= 3000:
        x, y, w, h = cv2.boundingRect(contour)
        subImg = frame[y:y+h, x:x+w]
        cv2.rectangle(frame,
                      (x, y), (x + w, y + h),
                      (0, 255, 0),
                      2)

Current output image (video) Desired output image with desired bounding box in red

After finding and sorting the contours, you need to use cv2.minAreaRect() function. This draws a rectangle enclosing each contour with the least area:

import numpy as np

# portion of code to find and sort contours

for contour in contours:
    area = cv2.contourArea(contour)
    if area >= 3000:
        rect = cv2.minAreaRect(cnt)
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        cv2.drawContours(frame, [box], 0, (0, 255, 0), 2)

Note: cv2.minAreaRect() returns properties of the rotated rectangle (center, dimensions and angle of rotation). cv2.boxPoints() is used to obtain the vertices of the rectangle. This is then passed into cv2.drawContours() to draw them.

Have a look at the documentation

For details on the algorithm:

Update:

The following code approximates a quadrilateral around a contour and draws it on frame . The variable value determines how strong you want your approximations to be:

# use a value between 0 and 1
value = 0.02
for c in contours:
    perimeter = cv2.arcLength(c, True)  
    approx = cv2.approxPolyDP(c, value*perimeter, True)    
    if len(approx) == 4:
        cv2.drawContours(frame, [approx], 0, (0, 0, 255), 5)

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