You can do as you are thinking more or less:
- load the image.
- convert to gray scale.
- apply some threshold.
- Calculate the contours.
- Look at the contours and check for shapes.
- segregate rectangles and filter by aspect ratio.
- you are done!
I used C++ to achieve this but I am sure you can convert it to python.
Mat image = imread("st.bmp");
if (image.empty())
return EXIT_FAILURE;
Mat gray;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
vector<vector<Point>> contoursgray;
vector<Vec4i> hierarchygray;
threshold(gray, gray, 200, 255, cv::THRESH_BINARY_INV);
findContours(gray, contoursgray, hierarchygray, RETR_TREE, CHAIN_APPROX_NONE);
// draw contours on the original image
Mat image_contour_gray = image.clone();
//drawContours( image_contour_gray, contoursgray, -1, Scalar(0, 255, 0), 2);
vector<vector<Point>> contoursgray2;
for (auto points : contoursgray) {
double peri = cv::arcLength(points, true);
vector<Point> aprox;
cv::approxPolyDP(points, aprox, 0.04 * peri, true);
if (aprox.size() == 4)
{
cv::Rect rect = cv::boundingRect(aprox);
if (rect.width / rect.height > 1.5) {
std::cout << rect.x << " " << rect.y << " " << rect.width << " " << rect.height << std::endl;
contoursgray2.push_back(aprox);
}
}
}
if (contoursgray2.size() > 0) {
drawContours(image_contour_gray, contoursgray2, -1, Scalar(0, 255, 0), 2);
imshow("Contour detection using gray conversion", image_contour_gray);
}
waitKey(0);
imwrite("gray.jpg", image_contour_gray);
destroyAllWindows();
This gives me the following image as output:
And it also outputs the following rectangles(x, y, w, h) on the command prom:
I have taken the tutorial from opencv webpage and changed the following lines:
contours_poly = [None]*len(contours)
#boundRect = [None]*len(contours)
boundRect = list()
centers = [None]*len(contours)
radius = [None]*len(contours)
for i, c in enumerate(contours):
contours_poly[i] = cv.approxPolyDP(c, 3, True)
if len(contours_poly[i]) == 4:
boundRect.append(cv.boundingRect(contours_poly[i]))
#boundRect[i] = cv.boundingRect(contours_poly[i])
#centers[i], radius[i] = cv.minEnclosingCircle(contours_poly[i])
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
#for i in range(len(contours)):
# color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
# cv.drawContours(drawing, contours_poly, i, color)
# cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])),
# (int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2)
#cv.circle(drawing, (int(centers[i][0]), int(centers[i][1])), int(radius[i]), color, 2)
for i in range(len(boundRect)):
if boundRect[i][2]/boundRect[i][3] > 2:
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])),
(int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2)
print(f'Rectangle X:{boundRect[i][0]}, Y:{boundRect[i][1]}, W:{boundRect[i][2]}, H:{boundRect[i][3]}')