Reputation: 11
I need to get the minimal angled rectangle enclosing all black pixels of an image.
Target images are scanned monochrome comic/manga pages that can be in any position (translated and rotated).
The desired result is similar to the following snippet when all black pixels are connected:
_, mono = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(255-mono, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
rect = cv2.minAreaRect(contours[0])
In other words, I need to get the minAreaRect
of the union of all contours, not only for one of them.
How can I do it using Python OpenCV?
Upvotes: 1
Views: 254
Reputation: 18895
To keep your idea using the contours found by cv2.findContours
, you just need to merge all of your contours, e.g. using np.vstack
. Since you only need the plain coordinates for cv2.minAreaRect
, merging them should be fine. To get the four vertices of the rotated rectangle, use cv2.boxPoints
. Finally, drawing can be done with cv2.polylines
.
Here's some short code snippet with a minimal example:
import cv2
import numpy as np
# Some test image
image = 255 * np.ones((300, 300), np.uint8)
cv2.circle(image, (100, 60), 30, 0, 1)
cv2.circle(image, (200, 200), 60, 0, 1)
# Find contours (with respect to OpenCV version); merge them
cnts = cv2.findContours(255-image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = np.vstack(cnts)
# Calculate minAreaRect of merged contours; determine points
pts = np.int32(cv2.boxPoints(cv2.minAreaRect(cnts)))
cv2.polylines(image, [pts], True, 192)
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
That'd be the image:
Hope that helps!
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.8.1
NumPy: 1.18.1
OpenCV: 4.1.2
----------------------------------------
Upvotes: 4