Python OpenCV 如何从二值图像中检测白色物体并将其裁剪?

4
我的目标是从这个二进制图像中检测出一张白纸,然后裁剪这张白纸并创建一个新的子集二进制图像。现在我的Python代码使用OpenCV可以找到这张白纸。首先,我创建了一个掩模来查找这张白纸。如你们所见,小的白噪声和小块已经被移除。然后问题变成了如何从这个二进制图像中裁剪这张白纸对象以创建一个新的子集二进制图像?我的当前代码是:
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) 

寻找cnt变量,有四个元素,但对我来说都是无意义的。我使用代码来适应一个框:

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

盒子信息似乎不正确。

感谢任何建议。

后续: 我已经解决了这个问题,非常简单。 代码附在下面:

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)
2个回答

1
contour对象是一个任意的点向量(列表),用于封闭检测到的对象。
一种简单的方法是在阈值处理后遍历所有像素并复制白色像素。
我相信findContours()会改变图像(副作用),所以请检查QR。
然而,通常需要获取最大的轮廓。例如:
# 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)

是的,QR码已经被改成了一组点,这些点是原始图像的边界。我真正想做的是找到一个边界框,以便我可以使用这个边界框裁剪图像。我希望得到一张只包含那张白纸的图像。 - Nan An
我没有包含裁剪/遮罩的代码,但也许以上内容会有所帮助。我认为您想从发现的轮廓中选择“最佳”轮廓,在这种情况下,我只选择了最大的一个。 - don_q

0

我其实已经找到了这个问题的解决方案,而且显然非常简单!!

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接