Reputation: 29
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()
Upvotes: 2
Views: 3381
Reputation: 2831
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!
Upvotes: 4