'How to detect and extract rectangles with Python OpenCV?
I am trying to detect three rectangles from the contour. I have already extracted the entire contour from the whole image. I am attaching the image of extracted contour below. I would like to figure out a way to further extract three rectangular kind panels from the whole contour.
Extracted Contour Image:
Solution 1:[1]
Here's a simple approach:
- Convert image to grayscale
- Threshold to obtain binary image
- Perform morphological operations to smooth image
- Find contours and extract ROI
After converting to grayscale, we threshold to obtain a binary image
image = cv2.imread('1.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY)[1]
Next we create a kernel and perform morphological operations to smooth the image. This step "breaks" the joints connecting the three rectangles by eroding the image
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,25))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)
From here we find contours and extract the ROI with numpy slicing. The bounding boxes for the desired rectangles are drawn on the original image
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
image_number = 0
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
ROI = original[y:y+h, x:x+w]
cv2.imwrite("ROI_{}.png".format(image_number), ROI)
image_number += 1
Here's each individual saved ROI
Full code
import cv2
image = cv2.imread('1.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,25))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
image_number = 0
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
ROI = original[y:y+h, x:x+w]
cv2.imwrite("ROI_{}.png".format(image_number), ROI)
image_number += 1
cv2.imshow('opening', opening)
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
Solution 2:[2]
This looks like a case for opening with a kernel sufficiently large to erode the lines in between your rectangles.
Another way would be to do the erode
multiple times and then call dilate
the same number of times.
A little suggestion, you might want to apply a thresh-hold on your image, because it looks like you have some noise (especially on the left and top rectangles).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | nathancy |
Solution 2 | Zlatomir |