7

I am new to OpenCV and have a few questions. I need to detect a bottle or a can based on their shape. For this I am using a raspberry pi board and pi camera. The background is always black and does not change. I have tried many possible solutions to this problem but could not get satisfactory results. The things I have tried include edge detection, morphological transformations, matchShapes(), matchTemplate(). Please let me know if I can do this task efficiently and with maximum accuracy.

A sample image:

enter image description here

David
  • 15,894
  • 22
  • 55
  • 66
user3553000
  • 111
  • 1
  • 4
  • So there wont be any object in the scene, other than the bottle?. – Haris Apr 20 '14 at 03:25
  • There won't be any object other than a bottle or a can at a given time. – user3553000 Apr 20 '14 at 04:11
  • 1
    Then apply [binary invert threshold](http://docs.opencv.org/doc/tutorials/imgproc/threshold/threshold.html#threshold-binary-inverted) with low value, to get the foreground. – Haris Apr 20 '14 at 04:33
  • How do I decide a threshold value? How do I compare it with a standard can size and shape? – user3553000 Apr 20 '14 at 05:22
  • The threshold you can set very low as your background always black, also see the answer [here](http://stackoverflow.com/questions/22023923/shape-detection-in-python-using-opencv/22042006#22042006) and [here](http://stackoverflow.com/questions/11424002/how-to-detect-simple-geometric-shapes-using-opencv) for how to compare it with a standard can size and shape. – Haris Apr 20 '14 at 06:58
  • I checked both the links. But, it says it will work only for standard shapes. How can I use it to compare with a can or bottle? – user3553000 Apr 20 '14 at 08:58
  • So you have to compare the shape of can, but with what? – Haris Apr 20 '14 at 10:08
  • http://stackoverflow.com/questions/10168686/algorithm-improvement-for-coca-cola-can-shape-recognition?rq=1 – Haris Apr 21 '14 at 11:26

1 Answers1

4

I came up with an approach that may help! If you know more things about the can, i.e the width to height ratio it can be more robust by adjusting the rectangle size!

Approach

  • Convert image to HSV color space. Increase V by a factor of 2 in order to have more visible things.
  • Find Sobel derivatives in x and y direction. Compute magnitude with equal weight for both direction.
  • Threshold your image using Otsu method.
  • Apply Closing to you image.
  • Apply Canny edge detector.
  • Find Hough Line Transform.
  • Find Bounding Rectangle of your line image.
  • Superimpose it onto your image.(Finally done :P)

Code

image = cv2.imread('image3.jpg', cv2.IMREAD_COLOR)
original = np.copy(image)
if image is None:
    print 'Can not read/find the image.'
    exit(-1)

hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
H,S,V = hsv_image[:,:,0], hsv_image[:,:,1], hsv_image[:,:,2]
V = V * 2

hsv_image = cv2.merge([H,S,V])
image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2RGB)
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# plt.figure(), plt.imshow(image)

Dx = cv2.Sobel(image,cv2.CV_8UC1,1,0)
Dy = cv2.Sobel(image,cv2.CV_8UC1,0,1)
M = cv2.addWeighted(Dx, 1, Dy,1,0)

# plt.subplot(1,3,1), plt.imshow(Dx, 'gray'), plt.title('Dx')
# plt.subplot(1,3,2), plt.imshow(Dy, 'gray'), plt.title('Dy')
# plt.subplot(1,3,3), plt.imshow(M, 'gray'), plt.title('Magnitude')

ret, binary = cv2.threshold(M,10,255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# plt.figure(), plt.imshow(binary, 'gray')

binary = binary.astype(np.uint8)
binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20, 20)))
edges = cv2.Canny(binary, 50, 100)
# plt.figure(), plt.imshow(edges, 'gray')

lines = cv2.HoughLinesP(edges,1,3.14/180,50,20,10)[0]
output = np.zeros_like(M, dtype=np.uint8)
for line in lines:
    cv2.line(output,(line[0],line[1]), (line[2], line[3]), (100,200,50), thickness=2)
# plt.figure(), plt.imshow(output, 'gray')

points = np.array([np.transpose(np.where(output != 0))], dtype=np.float32)
rect = cv2.boundingRect(points)
cv2.rectangle(original,(rect[1],rect[0]), (rect[1]+rect[3], rect[0]+rect[2]),(255,255,255),thickness=2)
original = cv2.cvtColor(original,cv2.COLOR_BGR2RGB)
plt.figure(), plt.imshow(original,'gray')


plt.show()

NOTE: you can uncomment the lines for showing the result of each step! I just comment them for the sake of readability.

Result

Result Image

NOTE: If you know the aspect ratio of your can you can fix it better!

I hope that will help. Good Luck :)

Hadi
  • 5,328
  • 11
  • 46
  • 67
  • 1
    Thank you so much for your comment. I think I can compute the aspect ratio of a can or a bottle. I should compare the rectangle's height and width with standard can sizes. – user3553000 Apr 20 '14 at 19:47