Detecting a can or bottle in opencv

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:

在这里输入图像描述


I came up with an approach that may help! If you know more things about the can, ie 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

    结果图像

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

    I hope that will help. Good Luck :)

    链接地址: http://www.djcxy.com/p/79582.html

    上一篇: 如何在opencv中检测建筑和雕塑?

    下一篇: 在opencv中检测罐头或瓶子