Python OpenCV detect a white object from a binary image and crop it

Nan An picture Nan An · Jul 22, 2014 · Viewed 9.6k times · Source

My goal is detecting a piece of white paper from this binary image and then crop this white paper and make a new subset binary image just for this white paper. enter image description here

Now my Python code with OpenCV can find this white paper. For the first step, I created a mask for finding this white paper: enter image description here

As you guys can see, the small white noise and small piece have been removed. And then the problem become how I can crop this white paper object from this binary image for making a new subset binary image?

My current code is:

import cv2
import numpy as np

QR = cv2.imread('IMG_0352.TIF', 0) 
mask = np.zeros(QR.shape,np.uint8) 

contours, hierarchy = cv2.findContours(QR,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    if cv2.contourArea(cnt)>1000000:
        cv2.drawContours(mask,[cnt],0,255,-1) 

Looking for the cnt var, there are four elements, but they are nonsense to me. I used code to fit a box:

x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

The box information doesn't seem right.

Thanks for any suggestions.

Follow up: I have figured out this problem, which is very easy. The code is attached:

import cv2
import numpy as np


QR_orig = cv2.imread('CamR_IMG_0352.TIF', 0)
QR = cv2.imread('IMG_0352.TIF', 0) # read the QR code binary image as grayscale image to make sure only one layer
mask = np.zeros(QR.shape,np.uint8) # mask image the final image without small pieces

# using findContours func to find the none-zero pieces
contours, hierarchy = cv2.findContours(QR,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

# draw the white paper and eliminate the small pieces (less than 1000000 px). This px count is the same as the QR code dectection
for cnt in contours:
    if cv2.contourArea(cnt)>1000000:
        cv2.drawContours(mask,[cnt],0,255,-1) # the [] around cnt and 3rd argument 0 mean only the particular contour is drawn

        # Build a ROI to crop the QR
        x,y,w,h = cv2.boundingRect(cnt)
        roi=mask[y:y+h,x:x+w]
        # crop the original QR based on the ROI
        QR_crop = QR_orig[y:y+h,x:x+w]
        # use cropped mask image (roi) to get rid of all small pieces
        QR_final = QR_crop * (roi/255)

cv2.imwrite('QR_final.TIF', QR_final)

Answer

don_q picture don_q · Jul 22, 2014

the contour object is an arbitrary vector (list) of points that enclose the object detected.

An easy brain dead way of accomplishing this is to walk through all the pixels after your thresholding and simply copy the white ones.

I believe findContours() alters the image ( side effect ) so check QR.

However, you need to (usually) get the biggest contour. Example:

# Choose largest contour
best = 0
maxsize = 0
count = 0
for cnt in contours:
    if cv2.contourArea(cnt) > maxsize :
        maxsize = cv2.contourArea(cnt)
        best = count

    count = count + 1

x,y,w,h = cv2.boundingRect(cnt[best])
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)