简体   繁体   中英

How to detect cardboard boxes in images?

I am looking for a python solution.

I am using opencv to detect boxes in image, but I feel the results aren't consistent. The boxes should always be 2 dimensional, but might be a bit skew or white once in a while.

I am only able to detect boxes areas.

I tried this:

import cv2

# reading image
img = cv2.imread('cardboard.jpg')

# thresholding the image
ret,thresh = cv2.threshold(img, 127, 229, cv2.THRESH_TOZERO_INV)
edged = cv2.cvtColor(thresh, cv2.COLOR_BGR2GRAY)

# collectiong contours
_, contours,h = cv2.findContours(edged, cv2.RETR_TREE,
                    cv2.CHAIN_APPROX_SIMPLE)

# looping through contours
for cnt in contours:

    x, y, w, h = cv2.boundingRect(cnt)
    if w > 100 and h > 100:
        approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)

        if len(approx) < 6:
            cv2.drawContours(img_x,[cnt],0,(0,215,255),3)

cv2.imwrite('contours/img.jpg', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在此处输入图片说明

在此处输入图片说明

I tried your code and it kind of works only for the second image (identifies 8 out of 9 boxes) because your boxes have white labels and it makes a good contrast to the background. However it will not work for the first image uploaded.

In the second image your code doesn't identify all boxes due to variation in lighting (this causes problems with thresholding hence only 8 boxes detected) so I would advise to give a read on lighting for computer vision as it can simplify your coding a great deal. That being said I have made an alternation to your code to maybe give you an idea on how to proceed (comments are in the code)...I have tested it with the second image and it does identify all boxes but it still should be tested further. If you would like to detect boxes on both kind of images you posted it would need a different approach.

Code:

import cv2

# reading image
img = cv2.imread('boxes.jpg')

# thresholding the image
ret,thresh = cv2.threshold(img, 127, 229, cv2.THRESH_TOZERO)
edged = cv2.cvtColor(thresh, cv2.COLOR_BGR2GRAY)

# ADDED BINARY THRESHOLD
ret,thresh = cv2.threshold(edged,100,255,cv2.THRESH_BINARY)


# collectiong contours
_, contours,h = cv2.findContours(edged, cv2.RETR_TREE,
                    cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('img', thresh)

# looping through contours
for cnt in contours:

    x, y, w, h = cv2.boundingRect(cnt)
    if w > 50 and h > 50:

        #ADDED SIZE CRITERION TO REMOVE NOISES
        size = cv2.contourArea(cnt)
        if size > 500:

            #CHANGED DRAWING CONTOURS WITH RECTANGLE
            cv2.rectangle(img,(x,y),(x+w,y+h),(0,215,255),2)

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

Result:

在此处输入图片说明

EDIT:

I have made sample of code for the second image which could be useful in further attempts. First you make a range for thresholding the image and to upper threshold and drawing the contour.

在此处输入图片说明

Then you convert the image to HSV colorspace and find the color with cv2.inRange() .

在此处输入图片说明

Then fill it by searching the contour and drawing on it.

在此处输入图片说明

Finally drawing rectangles on the contours.

import cv2
import numpy as np

# reading image
img = cv2.imread('boxes.jpg')
img_x = img.copy()


for low_thresh in range(0,25):

    ret,thresh = cv2.threshold(img, low_thresh*10, 255, cv2.THRESH_TOZERO_INV)
    edged = cv2.cvtColor(thresh, cv2.COLOR_BGR2GRAY)
    _, contours,h = cv2.findContours(edged, cv2.RETR_TREE,
                        cv2.CHAIN_APPROX_SIMPLE)

    for cnt in contours:
        size = cv2.contourArea(cnt)
        if 500 < size < 50000:
            x, y, w, h = cv2.boundingRect(cnt)

            if w > 100 and h > 100:
                approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)

                if len(approx) < 6:
                    cv2.drawContours(img,[cnt],0,(0,215,255),3)

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

lower_yellow = np.array([25,50,50])
upper_yellow = np.array([50,255,255])
mask_yellow = cv2.inRange(hsv, lower_yellow, upper_yellow)
res_yellow = cv2.bitwise_and(img,img, mask=mask_yellow)
gray_yellow = cv2.cvtColor(res_yellow, cv2.COLOR_BGR2GRAY)
_,thresh_yellow = cv2.threshold(mask_yellow,10,255,cv2.THRESH_BINARY)
_, contours_yellow, hierarhy = cv2.findContours(thresh_yellow,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

for c in contours_yellow:
    size = cv2.contourArea(c)
    if size > 500:
        cv2.drawContours(thresh_yellow, [c], -1, 255, -1)

_, contours_yellow, hierarhy3 = cv2.findContours(thresh_yellow,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

for c in contours_yellow:
    size = cv2.contourArea(c)
    if size > 500:
        cv2.drawContours(thresh_yellow, [c], -1, 255, -1)
        x, y, w, h = cv2.boundingRect(c)
        cv2.rectangle(img_x,(x,y),(x+w,y+h),(0,255,0),2)

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

在此处输入图片说明

Hope it helps a bit. Cheers!

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