I am using OpenCV and python to work on a project that involves body tracking, and I am using HSV values to find a skin tone then draw a box around it.
However although I can find the tracked object and draw a box around it the rectangles are always vertical, and I would like to know if there is anyway angle the rectangles so they better show the detected object, somewhat like the minEnclosingCircle function, but using a rectangle
The images probably explain what I am looking for better. The boxes that I am getting are green, and what I'm looking for I have drawn on in yellow. As you can see the mask shows and angled rectangle would also better encompass the selected area. I have also included the original image.
My code is:
import numpy as np
import cv2
# Input image
image = cv2.imread('TestIn.png')
# Converts to grey for better reulsts
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Converts to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# HSV values
lower_skin = np.array([5,36,53])
upper_skin = np.array([19,120,125])
mask = cv2.inRange(hsv, lower_skin, upper_skin)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
# Finds contours
im2, cnts, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Draws contours
for c in cnts:
if cv2.contourArea(c) < 3000:
continue
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(image, (x,y), (x+w,y+h), (0, 255, 0), 2)
cv2.imshow('mask', mask)
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Input image:
Output image (output boxes in green, desired boxes in yellow):
The cv2. boundingRect() function of OpenCV is used to draw an approximate rectangle around the binary image. This function is used mainly to highlight the region of interest after obtaining contours from an image. As per the documentation there are two types of bounding rectangles: Straight Bounding Rectangle.
You need to use cv2.minAreaRect(...)
and then cv2.boxPoints(...)
to obtain a sequence of points representing the polygon in a format that can be used by other OpenCV drawing functions, such as cv2.drawContours(...)
or cv2.polylines(...)
.
Based on the example in OpenCV documentation I added few statements to your code to achieve the desired result:
import numpy as np
import cv2
# Input image
image = cv2.imread('oaHUs.jpg')
# Converts to grey for better reulsts
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Converts to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# HSV values
lower_skin = np.array([5,36,53])
upper_skin = np.array([19,120,125])
mask = cv2.inRange(hsv, lower_skin, upper_skin)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
# Finds contours
im2, cnts, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Draws contours
for c in cnts:
if cv2.contourArea(c) < 3000:
continue
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(image, (x,y), (x+w,y+h), (0, 255, 0), 2)
## BEGIN - draw rotated rectangle
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(image,[box],0,(0,191,255),2)
## END - draw rotated rectangle
cv2.imwrite('out.png', image)
Output:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With