在OpenCV中检测罐子或瓶子
我刚接触OpenCV,有一些问题想请教。我需要根据形状来识别瓶子或罐子。为此,我使用的是树莓派和树莓派摄像头。背景一直是黑色的,并且不会变化。我尝试了很多解决方案,但都没有得到满意的结果。我尝试过的包括边缘检测、形态学变换、matchShapes()和matchTemplate()等。请告诉我,是否有办法高效且准确地完成这个任务。
一张示例图片:
1 个回答
4
我想出了一个可能有帮助的方法!如果你对罐子的更多信息,比如宽高比有了解,可以通过调整矩形的大小来让这个方法更可靠!
方法
- 把图片转换成 HSV 颜色空间。将
V
值增加两倍,这样可以让更多的东西变得更明显。 - 在
x
和y
方向上找到 Sobel 导数。计算两个方向的大小时要保持相同的权重。 - 使用 Otsu 方法对你的图片进行阈值处理。
- 对你的图片应用 闭合操作。
- 使用 Canny 边缘检测器。
- 找到 霍夫变换。
- 找到你线条图像的边界矩形。
- 把它叠加到你的图片上。(终于完成了 :P)
代码
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()
注意:你可以取消注释每一步的结果显示代码!我只是为了让内容更易读而注释掉了它们。
结果
注意:如果你知道罐子的宽高比,可以更好地调整它!
希望这能帮到你。祝好运 :)