魔方机器人视觉 | 您所在的位置:网站首页 › 机器人识别不了的字 › 魔方机器人视觉 |
大家好,我是松鼠,好久不见啦,今天跟大家分享一下魔方机器人的视觉部分——opencv颜色识别。 先给自己叠个甲,因为这些知识都是自学的,所以本文只算是抛砖引玉,做的不够好的地方可以一起交流~ Vol.1 什么是魔方机器人? 相信大家都见过魔方吧?大家可以把魔方打乱,然后再把它扭回六个面。而魔方机器人就是可以把打乱的魔方进行复原的机器人。 Vol.2 什么是视觉? 机器视觉本质上是让机器人能感受到世界的信息,就像人用眼睛去看东西,机器也需要用摄像头去看东西,然后把信息转化为机器人需要做出的应答。 魔方机器人的视觉就是通过对颜色的识别,让机器人按照算法对魔方实现控制,使魔方在最短的步数之内复原。 ♬..~ ♫. ♪.. 话不多说,我们进入正题,我用的是opencv来识别颜色,接下来,我一定让有着一定基础的你有所收获! 首先我们举个例子,这是我从网上找到的一张魔方机器人摄像头拍摄到的图片。 很明显,这个视角看魔方很不直观,对于笨笨的机器人来说,这样的图片需要做一些处理才能让它识别。 我们可以通过透视变换来处理图像(简而言之就是把图片看魔方的视角变为正视): # 透视变换 width,height = 300,300 #设定图片大小 pts1 = np.float32([[25,68],[203,19],[32,309],[186,400]]) #划分第一张图的四个点 pts2 = np.float32([[210,20],[370,72],[196,400],[363,318]]) #划分第二张图的四个点 pts3 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第一张图片 pts4 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第二张图片 matrix1 = cv2.getPerspectiveTransform(pts1,pts3) imgOutput1 = cv2.warpPerspective(img,matrix1,(width,height)) #第一张图透视变换 matrix2 = cv2.getPerspectiveTransform(pts2,pts4) imgOutput2 = cv2.warpPerspective(img,matrix2,(width,height)) #第二张图透视变换透视变化以后: OK,现在我们得到了两张图片: 那么现在,我这里有两个方案去识别颜色: 1 通过边缘检测来识别魔方的格子(通过检测边缘,找出四边形即为魔方格子,检测格子颜色) 2 通过分割的手段来识别(把一张图片分割成九个部分,识别每个部分的颜色占比) ♬..♩~ ♫. ♪.. 通过实践发现,因为图片太模糊了,边缘检测的方法只能检测出少数几个格子。 很明显,效果不是很好,所以我在下面主要介绍分割的方法。 pic1 = imgOutput1[0:100,0:100] pic2 = imgOutput1[0:100,100:200] pic3 = imgOutput1[0:100,200:300] ... #以此类推因为我们已经设置了图片为(300,300),我们可以直接通过循环的方式分割9个格子: for i in range(3): for j in range(3): y_start = i*width//3 y_end = (i+1)*width//3 x_start = j * width // 3 x_end = (j + 1) * width // 3 pic = imgOutput1[y_start:y_end,x_start:x_end]这样会方便很多~ 然后格子就会单独成一张图片啦! 效果如下: (这是我通过cv2.imwrite保存得来的,有兴趣的朋友自己试试) ♬..♩~ ♫. ♪.. 看到这里,你已经离识别成功不远啦~ 接下来,我们的流程是: 1、先找出魔方各个颜色的HSV范围(这一点是基础) 2、把图片转为HSV格式 3、利用cv2.inRange函数设阈值,去除背景部分 4、利用cv2.countNonZero函数计算阈值内的比例,即颜色比例,超过某个值则判断为某个颜色 5、逻辑判断,判断颜色 我认为最让人头疼的就是问题就是:某个颜色的HSV值范围如何确定? 我这里是通过鼠标点击图片的事件去获取该点的HSV值,然后制定大概的范围作为某种颜色的HSV识别范围。 主要代码如下: def getpos(event,x,y,flags,param): if event==cv2.EVENT_LBUTTONDOWN: #定义一个鼠标左键按下去的事件 print(HSV[y,x]) cv2.setMouseCallback("imageHSV",getpos)#返回HSV值 话不多说上代码: for i in range(3): for j in range(3): y_start = i*width//3 y_end = (i+1)*width//3 x_start = j * width // 3 x_end = (j + 1) * width // 3 pic = imgOutput1[y_start:y_end,x_start:x_end] hsv = cv2.cvtColor(pic,cv2.COLOR_BGR2HSV) mask_red = cv2.inRange(hsv,red_min,red_max) red_bili = cv2.countNonZero(mask_red)/(pic.size/3) mask_yellow = cv2.inRange(hsv, yellow_min, yellow_max) yellow_bili = cv2.countNonZero(mask_yellow) / (pic.size / 3) mask_blue = cv2.inRange(hsv, blue_min, blue_max) blue_bili = cv2.countNonZero(mask_blue) / (pic.size / 3) mask_white = cv2.inRange(hsv, white_min, white_max) white_bili = cv2.countNonZero(mask_white) / (pic.size / 3) mask_orange = cv2.inRange(hsv, orange_min, orange_max) orange_bili = cv2.countNonZero(mask_orange) / (pic.size / 3) mask_green = cv2.inRange(hsv, green_min, green_max) green_bili = cv2.countNonZero(mask_green) / (pic.size / 3) if red_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:红") if yellow_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:黄") if blue_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:蓝") if white_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:白") if orange_bili >= 0.3: print("第一张图第"+str(3*i+j+1)+"个格子:橙") if green_bili >= 0.4: print("第一张图第" + str(3 * i + j + 1) + "个格子:绿")效果如下: 总代码: import cv2 import numpy as np img = cv2.imread('./cube.png') width,height = 300,300 #设定图片大小 yellow_min = np.array([30,40,150]) yellow_max = np.array([60,80,190]) red_min = np.array([3,240,90]) red_max = np.array([15,255,120]) blue_min = np.array([95,220,90]) blue_max = np.array([115,255,160]) white_min = np.array([110,9,160]) white_max = np.array([125,45,190]) orange_min = np.array([6,205,235]) orange_max = np.array([10,225,255]) green_min = np.array([80,240,100]) green_max = np.array([85,255,120]) pts1 = np.float32([[25,68],[203,19],[32,309],[186,400]]) #划分第一张图的四个点 pts2 = np.float32([[210,20],[370,72],[196,400],[363,318]]) #划分第二张图的四个点 pts3 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第一张图片 pts4 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第二张图片 # 透视变换 matrix1 = cv2.getPerspectiveTransform(pts1,pts3) imgOutput1 = cv2.warpPerspective(img,matrix1,(width,height)) #第一张图透视变换 matrix2 = cv2.getPerspectiveTransform(pts2,pts4) imgOutput2 = cv2.warpPerspective(img,matrix2,(width,height)) #第二张图透视变换 # cv2.imshow("原图",img) cv2.imshow("Output1",imgOutput1) cv2.imshow("Output2",imgOutput2) cv2.imwrite("./photos/Output1.png",imgOutput1) cv2.imwrite("./photos/Output2.png",imgOutput2) for i in range(3): for j in range(3): y_start = i*width//3 y_end = (i+1)*width//3 x_start = j * width // 3 x_end = (j + 1) * width // 3 pic = imgOutput1[y_start:y_end,x_start:x_end] hsv = cv2.cvtColor(pic,cv2.COLOR_BGR2HSV) mask_red = cv2.inRange(hsv,red_min,red_max) red_bili = cv2.countNonZero(mask_red)/(pic.size/3) mask_yellow = cv2.inRange(hsv, yellow_min, yellow_max) yellow_bili = cv2.countNonZero(mask_yellow) / (pic.size / 3) mask_blue = cv2.inRange(hsv, blue_min, blue_max) blue_bili = cv2.countNonZero(mask_blue) / (pic.size / 3) mask_white = cv2.inRange(hsv, white_min, white_max) white_bili = cv2.countNonZero(mask_white) / (pic.size / 3) mask_orange = cv2.inRange(hsv, orange_min, orange_max) orange_bili = cv2.countNonZero(mask_orange) / (pic.size / 3) mask_green = cv2.inRange(hsv, green_min, green_max) green_bili = cv2.countNonZero(mask_green) / (pic.size / 3) if red_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:红") if yellow_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:黄") if blue_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:蓝") if white_bili >= 0.4: print("第一张图第"+str(3*i+j+1)+"个格子:白") if orange_bili >= 0.3: print("第一张图第"+str(3*i+j+1)+"个格子:橙") if green_bili >= 0.4: print("第一张图第" + str(3 * i + j + 1) + "个格子:绿") for i in range(3): for j in range(3): y_start = i*width//3 y_end = (i+1)*width//3 x_start = j * width // 3 x_end = (j + 1) * width // 3 pic = imgOutput2[y_start:y_end,x_start:x_end] hsv = cv2.cvtColor(pic,cv2.COLOR_BGR2HSV) mask_red = cv2.inRange(hsv,red_min,red_max) red_bili = cv2.countNonZero(mask_red)/(pic.size/3) mask_yellow = cv2.inRange(hsv, yellow_min, yellow_max) yellow_bili = cv2.countNonZero(mask_yellow) / (pic.size / 3) mask_blue = cv2.inRange(hsv, blue_min, blue_max) blue_bili = cv2.countNonZero(mask_blue) / (pic.size / 3) mask_white = cv2.inRange(hsv, white_min, white_max) white_bili = cv2.countNonZero(mask_white) / (pic.size / 3) mask_orange = cv2.inRange(hsv, orange_min, orange_max) orange_bili = cv2.countNonZero(mask_orange) / (pic.size / 3) mask_green = cv2.inRange(hsv, green_min, green_max) green_bili = cv2.countNonZero(mask_green) / (pic.size / 3) if red_bili >= 0.4: print("第二张图第"+str(3*i+j+1)+"个格子:红") if yellow_bili >= 0.4: print("第二张图第"+str(3*i+j+1)+"个格子:黄") if blue_bili >= 0.4: print("第二张图第"+str(3*i+j+1)+"个格子:蓝") if white_bili >= 0.4: print("第二张图第"+str(3*i+j+1)+"个格子:白") if orange_bili >= 0.3: print("第二张图第"+str(3*i+j+1)+"个格子:橙") if green_bili >= 0.4: print("第二张图第" + str(3 * i + j + 1) + "个格子:绿") cv2.waitKey(0) cv2.destroyAllWindows()最终效果: 开源!opencv魔方机器人视觉教程 每一个格子都能准确识别出来,我们的视觉部分就差不多完成了,剩下的就是电控+机械部分啦~ ♬..♩~ ♫. ♪.. 因为篇幅太长了,很多细节我没有细说,有空我会单独把透视变化和HSV阈值的确定和大家分享的,还有需要源文件的朋友可以在公众号【松鼠小铺子】回复“颜色识别”就可以获取啦~ 来咯来咯~ 有帮助的话点个赞吧~ |
CopyRight 2018-2019 实验室设备网 版权所有 |