我正在从事一个机器人项目,我们需要实现某种形式的图像识别来找到正确的路径。有一个旋转的盘子,显示方向如下:
我编写了下面的代码,成功地使用网络摄像头捕获视频流,并尝试从提供的模板中找到盘子的图像:
import cv2
IMGn = cv2.imread("North.png",0)
webcam = cv2.VideoCapture(0)
grayScale = True
key = 0
def transformation(frame,template):
w, h = template.shape[::-1]
res = cv2.matchTemplate(frame,template,cv2.TM_SQDIFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = min_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(frame,top_left, bottom_right, 255, 2)
return frame
while (key!=ord('q')):
check, frame = webcam.read()
if(grayScale):
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = transformation(frame,IMGn)
cv2.imshow("Capturing", frame)
key = cv2.waitKey(1)
webcam.release()
cv2.destroyAllWindows()
这个方法并不是非常有效,但至少可以找到指南针的大致轮廓。然而,我不确定如何找到圆的旋转角度!此外,大小似乎也是一个问题(当距离太远或太近时,跟踪会出现问题)。这是我第一次尝试图像识别,所以请尽量简化你的回答。谢谢。
我在使用cv2.findContours时遇到了问题。它似乎返回3个值,而不是2个。除此之外,代码成功检测和裁剪了图像,但无法在最后一步找到线条。还有一个问题,如果图片旋转超过180度,它将给出错误的结果,因为线条已经旋转了超过180度。使用黑色正方形内部的小白色正方形应该可以解决这个问题,并根据情况为图像添加180度偏移,但我也不确定如何做到这一点。
import cv2
webcam = cv2.VideoCapture(0)
def find_disk(frame,template):
w, h = template.shape[::-1]
res = cv2.matchTemplate(frame,template,cv2.TM_SQDIFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = min_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
frame = frame[top_left[1]:bottom_right[1],top_left[0]:bottom_right[0]]
return frame
def thresh_img(frame):
frame = cv2.GaussianBlur(frame, (5, 5), 0)
ret, thresh = cv2.threshold(frame, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
return thresh
def crop_disk(frame):
_, contours, hierarchy = cv2.findContours(frame, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
areas = []
for cnt in contours:
area = cv2.contourArea(cnt)
areas.append((area, cnt))
areas.sort(key=lambda x: x[0], reverse=True)
areas.pop(0) # remove biggest contour
if (len(areas)>0):
x, y, w, h = cv2.boundingRect(areas[0][1]) # get bounding rectangle around biggest contour to crop to
crop = frame[y:y+h, x:x+w]
else:
crop = frame
return crop
def find_lines(frame):
edges = cv2.Canny(frame, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
if (lines!=None):
print(lines)
img = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR) # Convert cropped black and white image to color to draw the red line
for rho, theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
return cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
else:
return frame
key = 0
while (key!=ord('q')):
check, frame = webcam.read()
if(grayScale):
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = find_lines(crop_disk(thresh_img(find_disk(frame,IMGn))))
cv2.imshow("Capturing", frame)
key = cv2.waitKey(1)
#key = ord('q')
webcam.release()
cv2.destroyAllWindows()
这里有一张示例输出的图片(我是通过在手机上拍摄磁盘图片并将其在相机前旋转得到的):