简体   繁体   中英

Python, OpenCV and rectangles on scanned image

image with rectangles

Hello! Mastering OpenCV, I encountered a problem: I can't find any of these boxes to them then cut. Tell me, please, what filters and logic to use?

#!/usr/bin/env python
import cv2
import os

img_path = os.path.join('img', '1.jpg')
image = cv2.imread(img_path)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)

cv2.imshow('gray', gray)
cv2.waitKey(0)

cv2.imshow('edged', edged)
cv2.waitKey(0)


(_, cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)

    if len(approx) == 4:
        cv2.drawContours(image, [approx], -1, (0, 255, 0), 3)


cv2.imshow('result', image)
cv2.waitKey(0)

This example finds a lot of garbage, and all rectangles (not just those with background)

EDIT: OpenСV duplicates rectangle contours. How can i cut off duplicates?

You are very close to the solution, while iterating the contours in for c in cnts: you are filtering contours on the basis of number of sides of polygon approximated from the contour, You just need to add filter for contour area as well in order to remove the smaller rectangles being detected, which can be done as:

for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)

    if len(approx) == 4 and cv2.contourArea(c) > 200:
        cv2.drawContours(image, [approx], -1, (0, 255, 0), 3)

You can use adaptive thresholding as a pre-processing step followed by gaussian blur before applying canny edge detection.

import cv2
import numpy as np

img = cv2.imread('image with boxes.jpg')
blur = cv2.GaussianBlur(img,(7,7),0)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
mask = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
canny = cv2.Canny(mask, 30, 200)
(_, cnts, _) = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)

    if len(approx) == 4:
        cv2.drawContours(img, [approx], -1, (0, 0, 255), 1)

cv2.imshow('result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

最终形象

As you can see no rectangles are allocated which do not have any background

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