Wes*_*ley 3 python opencv image-processing pattern-matching
我在使用opencv检测正方形时遇到问题。
第一张图片:
第二张图片:
这是我使用的代码(对不起,格式较差):
#!/usr/bin/env python
# coding: utf-8
import numpy as np
import cv2
import argparse
import math
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to input image")
args = vars(ap.parse_args())
img = cv2.imread(args["image"])
# img = cv2.bitwise_not(img,img)
# gray = cv2.imread(args["image"],0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# gray = cv2.GaussianBlur(gray, (5, 5), 0)
cv2.imshow('gray', gray)
cv2.waitKey(0)
ret, thresh = cv2.threshold(gray, 230, 255, 1)
cv2.imshow('thresh', thresh)
# cv2.imwrite('./wni230.png',thresh)
cv2.waitKey(0)
square_cnts = []
##################################################
shape = cv2.imread('./shape1.png')
shape_gray = cv2.cvtColor(shape, cv2.COLOR_BGR2GRAY)
ret, shape_thresh = cv2.threshold(shape_gray, 0, 255, 0)
tmpimage, contours, h = cv2.findContours(shape_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
shape_cnt0 = contours[0]
shape_approx = []
for i in contours:
approx = cv2.approxPolyDP(i, 0.01*cv2.arcLength(i, True), True)
# print len(approx)
if len(approx) == 4:
shape_approx.append(len(approx))
##################################################
# tmpimage,contours,h = cv2.findContours(thresh,1,2)
# cv2.RETR_TREE
tmpimage, contours, h = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt0 = contours[0]
# from skimage import measure
# contours = measure.find_contours(thresh, 0.8)
for cnt in contours[::-1]:
print cv2.arcLength(cnt, True)
print cnt
approx = cv2.approxPolyDP(cnt, 0.1*cv2.arcLength(cnt, True), True)
print len(approx)
if len(approx) == 5:
print "pentagon"
cv2.drawContours(img, [cnt], 0, 255, 2)
cv2.imshow('tmppentagon', img)
cv2.waitKey(0)
elif len(approx) == 3:
print "triangle"
cv2.drawContours(img, [cnt], 0, (0, 255, 0), 2)
cv2.imshow('tmptriangle', img)
cv2.waitKey(0)
elif len(approx) == 2:
print 'approx:'
print approx
ret = cv2.matchShapes(cnt, cnt0, 1, 0.0)
print 'match shape ret:%s' % ret
print "two approx line"
cv2.drawContours(img, [cnt], 0, (0, 255, 0), 2)
cv2.imshow('twoline?', img)
cv2.waitKey(0)
elif len(approx) == 4:
ret = cv2.matchShapes(cnt, cnt0, 1, 0.0)
print 'match shape ret:%s' % ret
if ret > 0.5:
print "Parallelogram"
elif 0.3 < ret < 0.5:
print "Rectangle"
elif 0 < ret < 0.3:
print "Rhombus"
else:
print "square"
print cv2.arcLength(cnt, True)
print approx
cv2.drawContours(img, [approx], 0, (0, 0, 255), 2)
cv2.imshow('tmpsquare', img)
cv2.waitKey(0)
if int(cv2.arcLength(cnt, True)) >= 96:
if math.fabs(math.sqrt((approx[0][0][0]-approx[1][0][0])**2+(approx[0][0][1]-approx[1][0][1])**2) - math.sqrt((approx[1][0][0]-approx[2][0][0])**2+(approx[1][0][1]-approx[2][0][1])**2)) <= 5:
x, y, w, h = cv2.boundingRect(cnt)
cv2.imshow('final',img[y:y+h,x:x+w])
cv2.waitKey(0)
print 'target but long squere detected...'
cv2.waitKey(0)
elif len(approx) == 9:
print "half-circle"
cv2.drawContours(img,[cnt],0,(255,255,0),2)
cv2.imshow('tmphalfcircle',img)
cv2.waitKey(0)
elif len(approx) > 15:
print "circle"
cv2.drawContours(img,[cnt],0,(0,255,255),2)
cv2.imshow('tmpcircle',img)
cv2.waitKey(0)
cv2.imshow('img', img)
cv2.imwrite('tmp.png', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)第一个结果:
第二个结果:
python 2.7.10
OpenCV的3.2.0
为什么两个图像的cv2.approxPolyDP的长度总是2,而不是4?我希望结果是图像中正方形的4。
为什么我的cv2.matchShapes结果如此不同?我认为理想的输出是0,但是为什么与第二张图像匹配会产生这么高的数字?
浏览有关这些函数的文档,似乎approxPolyDP返回2,因为它只能找到2个点的轮廓,这些轮廓实际上按照您所描述的方式连接多边形。看一下Ramer-Douglas-Peucker算法,它是polyDP的基础。同样,如果两个匹配的形状之间有很多差异,shapeMatch结果也很高。通常,除非形状确实不同,否则该值不会太大,但是在这种情况下,您似乎与第二张图像的轮廓相匹配!
看这里:
tmpimage, contours, h = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt0 = contours[0]
Run Code Online (Sandbox Code Playgroud)
cnt0是第二个图像中的第一个轮廓。现在进一步说:
elif len(approx) == 2:
print 'approx:'
print approx
ret = cv2.matchShapes(cnt, cnt0, 1, 0.0)
Run Code Online (Sandbox Code Playgroud)
您正在将提供的图像中的第一个图像与同一图像中的轮廓进行比较!您的第一个轮廓的差异为零,因为它恰好是图像中的第一个轮廓,而在其他测试图像中该轮廓出现的可能性更高,因此发生的可能性较小,因此您不会获得匹配。
此外,由于轮廓未连接/从正确的位置开始,似乎永远也不会得到四个点approxPolyDP。为了向自己证明这一点,请在循环顶部使用以下代码:
for cnt in contours[::-1]:
print cv2.arcLength(cnt, True)
approx_polygon_shape = cv2.approxPolyDP(cnt, 0.087 * cv2.arcLength(cnt, True), True)
print "number of approx points", len(approx_polygon_shape)
print "approx shape", approx_polygon_shape
tempimage = input_image.copy()
cv2.drawContours(tempimage, [approx_polygon_shape], -1, (0,255,0), 1)
cv2.imshow("polyshape show", tempimage)
cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)
无论我用什么数字来修改roxPolyDP中的第二个参数epsilon,我都无法得到4分。我会得到三角形或大量的点(我相信这个点恰好是六个)。在您的普通代码中,您将弧长增加了0.1,在这种情况下,事实证明,每个轮廓通常只会给您2个点!
对我来说,这返回:
似乎是导致问题的右上角空白区域,您可能需要模糊处理,然后再查看代码,就好像您已经知道这可能是问题一样。重新添加在此处标记的注释行:
img = cv2.imread(args["image"])
# img = cv2.bitwise_not(img,img)
# gray = cv2.imread(args["image"],0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#UNCOMMENT!!!VVV
gray = cv2.GaussianBlur(gray, (5, 5), 0)
cv2.imshow('gray', gray)
cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)
即使使用普通0.1乘法,也只允许选择四个点就足够模糊(示例输出,请注意,我不使用python2并稍微修改了代码以获得更合理的输出):
在第二张图片上尝试模糊技巧也可以!
如果您看一下实际的灰度图像,这是可行的,因为它模糊得足以允许轮廓足够接近,以使roxPolyDP起作用并“跳过”之前引起问题的小间隙。这是模糊图像的样子: