当前位置:   article > 正文

魔方机器人视觉——魔方opencv颜色识别分享_opencv魔方颜色聚类分析

opencv魔方颜色聚类分析

    大家好,我是松鼠,好久不见啦,今天跟大家分享一下魔方机器人的视觉部分——opencv颜色识别。

        先给自己叠个甲,因为这些知识都是自学的,所以本文只算是抛砖引玉,做的不够好的地方可以一起交流~

Vol.1

什么是魔方机器人

    相信大家都见过魔方吧?大家可以把魔方打乱,然后再把它扭回六个面。而魔方机器人就是可以把打乱的魔方进行复原的机器人。

Vol.2

什么是视觉?

    机器视觉本质上是让机器人能感受到世界的信息,就像人用眼睛去看东西,机器也需要用摄像头去看东西,然后把信息转化为机器人需要做出的应答。

    魔方机器人的视觉就是通过对颜色的识别,让机器人按照算法对魔方实现控制,使魔方在最短的步数之内复原。

♬..~ ♫. ♪..

    话不多说,我们进入正题,我用的是opencv来识别颜色,接下来,我一定让有着一定基础的你有所收获!

    首先我们举个例子,这是我从网上找到的一张魔方机器人摄像头拍摄到的图片。

    很明显,这个视角看魔方很不直观,对于笨笨的机器人来说,这样的图片需要做一些处理才能让它识别。

    我们可以通过透视变换来处理图像(简而言之就是把图片看魔方的视角变为正视):

  1. # 透视变换
  2. width,height = 300,300 #设定图片大小
  3. pts1 = np.float32([[25,68],[203,19],[32,309],[186,400]]) #划分第一张图的四个点
  4. pts2 = np.float32([[210,20],[370,72],[196,400],[363,318]]) #划分第二张图的四个点
  5. pts3 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第一张图片
  6. pts4 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第二张图片
  7. matrix1 = cv2.getPerspectiveTransform(pts1,pts3)
  8. imgOutput1 = cv2.warpPerspective(img,matrix1,(width,height)) #第一张图透视变换
  9. matrix2 = cv2.getPerspectiveTransform(pts2,pts4)
  10. imgOutput2 = cv2.warpPerspective(img,matrix2,(width,height)) #第二张图透视变换

    透视变化以后:

    OK,现在我们得到了两张图片:

    那么现在,我这里有两个方案去识别颜色:

        1 通过边缘检测来识别魔方的格子(通过检测边缘,找出四边形即为魔方格子,检测格子颜色)

        2 通过分割的手段来识别(把一张图片分割成九个部分,识别每个部分的颜色占比)

♬..♩~ ♫. ♪..

    通过实践发现,因为图片太模糊了,边缘检测的方法只能检测出少数几个格子。

    很明显,效果不是很好,所以我在下面主要介绍分割的方法。

  1. pic1 = imgOutput1[0:100,0:100]
  2. pic2 = imgOutput1[0:100,100:200]
  3. pic3 = imgOutput1[0:100,200:300]
  4. ...
  5. #以此类推

    因为我们已经设置了图片为(300,300),我们可以直接通过循环的方式分割9个格子:

  1. for i in range(3):
  2.    for j in range(3):
  3.        y_start = i*width//3
  4.        y_end = (i+1)*width//3
  5.        x_start = j * width // 3
  6.        x_end = (j + 1) * width // 3
  7.        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识别范围。

    主要代码如下:

  1. def getpos(event,x,y,flags,param):
  2.    if event==cv2.EVENT_LBUTTONDOWN: #定义一个鼠标左键按下去的事件
  3.        print(HSV[y,x])
  4. cv2.setMouseCallback("imageHSV",getpos)#返回HSV值

​​​​   话不多说上代码:

  1. for i in range(3):
  2.    for j in range(3):
  3.        y_start = i*width//3
  4.        y_end = (i+1)*width//3
  5.        x_start = j * width // 3
  6.        x_end = (j + 1) * width // 3
  7.        pic = imgOutput1[y_start:y_end,x_start:x_end]
  8.        hsv = cv2.cvtColor(pic,cv2.COLOR_BGR2HSV)
  9.        mask_red = cv2.inRange(hsv,red_min,red_max)
  10.        red_bili = cv2.countNonZero(mask_red)/(pic.size/3)
  11.        mask_yellow = cv2.inRange(hsv, yellow_min, yellow_max)
  12.        yellow_bili = cv2.countNonZero(mask_yellow) / (pic.size / 3)
  13.        mask_blue = cv2.inRange(hsv, blue_min, blue_max)
  14.        blue_bili = cv2.countNonZero(mask_blue) / (pic.size / 3)
  15.        mask_white = cv2.inRange(hsv, white_min, white_max)
  16.        white_bili = cv2.countNonZero(mask_white) / (pic.size / 3)
  17.        mask_orange = cv2.inRange(hsv, orange_min, orange_max)
  18.        orange_bili = cv2.countNonZero(mask_orange) / (pic.size / 3)
  19.        mask_green = cv2.inRange(hsv, green_min, green_max)
  20.        green_bili = cv2.countNonZero(mask_green) / (pic.size / 3)
  21.        if red_bili >= 0.4:
  22.            print("第一张图第"+str(3*i+j+1)+"个格子:红")
  23.        if yellow_bili >= 0.4:
  24.            print("第一张图第"+str(3*i+j+1)+"个格子:黄")
  25.        if blue_bili >= 0.4:
  26.            print("第一张图第"+str(3*i+j+1)+"个格子:蓝")
  27.        if white_bili >= 0.4:
  28.            print("第一张图第"+str(3*i+j+1)+"个格子:白")
  29.        if orange_bili >= 0.3:
  30.            print("第一张图第"+str(3*i+j+1)+"个格子:橙")
  31.        if green_bili >= 0.4:
  32.            print("第一张图第" + str(3 * i + j + 1) + "个格子:绿")

    效果如下:

总代码:

  1. import cv2
  2. import numpy as np
  3. img = cv2.imread('./cube.png')
  4. width,height = 300,300 #设定图片大小
  5. yellow_min = np.array([30,40,150])
  6. yellow_max = np.array([60,80,190])
  7. red_min = np.array([3,240,90])
  8. red_max = np.array([15,255,120])
  9. blue_min = np.array([95,220,90])
  10. blue_max = np.array([115,255,160])
  11. white_min = np.array([110,9,160])
  12. white_max = np.array([125,45,190])
  13. orange_min = np.array([6,205,235])
  14. orange_max = np.array([10,225,255])
  15. green_min = np.array([80,240,100])
  16. green_max = np.array([85,255,120])
  17. pts1 = np.float32([[25,68],[203,19],[32,309],[186,400]]) #划分第一张图的四个点
  18. pts2 = np.float32([[210,20],[370,72],[196,400],[363,318]]) #划分第二张图的四个点
  19. pts3 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第一张图片
  20. pts4 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #转化为第二张图片
  21. # 透视变换
  22. matrix1 = cv2.getPerspectiveTransform(pts1,pts3)
  23. imgOutput1 = cv2.warpPerspective(img,matrix1,(width,height)) #第一张图透视变换
  24. matrix2 = cv2.getPerspectiveTransform(pts2,pts4)
  25. imgOutput2 = cv2.warpPerspective(img,matrix2,(width,height)) #第二张图透视变换
  26. # cv2.imshow("原图",img)
  27. cv2.imshow("Output1",imgOutput1)
  28. cv2.imshow("Output2",imgOutput2)
  29. cv2.imwrite("./photos/Output1.png",imgOutput1)
  30. cv2.imwrite("./photos/Output2.png",imgOutput2)
  31. for i in range(3):
  32.    for j in range(3):
  33.        y_start = i*width//3
  34.        y_end = (i+1)*width//3
  35.        x_start = j * width // 3
  36.        x_end = (j + 1) * width // 3
  37.        pic = imgOutput1[y_start:y_end,x_start:x_end]
  38.        hsv = cv2.cvtColor(pic,cv2.COLOR_BGR2HSV)
  39.        mask_red = cv2.inRange(hsv,red_min,red_max)
  40.        red_bili = cv2.countNonZero(mask_red)/(pic.size/3)
  41.        mask_yellow = cv2.inRange(hsv, yellow_min, yellow_max)
  42.        yellow_bili = cv2.countNonZero(mask_yellow) / (pic.size / 3)
  43.        mask_blue = cv2.inRange(hsv, blue_min, blue_max)
  44.        blue_bili = cv2.countNonZero(mask_blue) / (pic.size / 3)
  45.        mask_white = cv2.inRange(hsv, white_min, white_max)
  46.        white_bili = cv2.countNonZero(mask_white) / (pic.size / 3)
  47.        mask_orange = cv2.inRange(hsv, orange_min, orange_max)
  48.        orange_bili = cv2.countNonZero(mask_orange) / (pic.size / 3)
  49.        mask_green = cv2.inRange(hsv, green_min, green_max)
  50.        green_bili = cv2.countNonZero(mask_green) / (pic.size / 3)
  51.        if red_bili >= 0.4:
  52.            print("第一张图第"+str(3*i+j+1)+"个格子:红")
  53.        if yellow_bili >= 0.4:
  54.            print("第一张图第"+str(3*i+j+1)+"个格子:黄")
  55.        if blue_bili >= 0.4:
  56.            print("第一张图第"+str(3*i+j+1)+"个格子:蓝")
  57.        if white_bili >= 0.4:
  58.            print("第一张图第"+str(3*i+j+1)+"个格子:白")
  59.        if orange_bili >= 0.3:
  60.            print("第一张图第"+str(3*i+j+1)+"个格子:橙")
  61.        if green_bili >= 0.4:
  62.            print("第一张图第" + str(3 * i + j + 1) + "个格子:绿")
  63. for i in range(3):
  64.    for j in range(3):
  65.        y_start = i*width//3
  66.        y_end = (i+1)*width//3
  67.        x_start = j * width // 3
  68.        x_end = (j + 1) * width // 3
  69.        pic = imgOutput2[y_start:y_end,x_start:x_end]
  70.        hsv = cv2.cvtColor(pic,cv2.COLOR_BGR2HSV)
  71.        mask_red = cv2.inRange(hsv,red_min,red_max)
  72.        red_bili = cv2.countNonZero(mask_red)/(pic.size/3)
  73.        mask_yellow = cv2.inRange(hsv, yellow_min, yellow_max)
  74.        yellow_bili = cv2.countNonZero(mask_yellow) / (pic.size / 3)
  75.        mask_blue = cv2.inRange(hsv, blue_min, blue_max)
  76.        blue_bili = cv2.countNonZero(mask_blue) / (pic.size / 3)
  77.        mask_white = cv2.inRange(hsv, white_min, white_max)
  78.        white_bili = cv2.countNonZero(mask_white) / (pic.size / 3)
  79.        mask_orange = cv2.inRange(hsv, orange_min, orange_max)
  80.        orange_bili = cv2.countNonZero(mask_orange) / (pic.size / 3)
  81.        mask_green = cv2.inRange(hsv, green_min, green_max)
  82.        green_bili = cv2.countNonZero(mask_green) / (pic.size / 3)
  83.        if red_bili >= 0.4:
  84.            print("第二张图第"+str(3*i+j+1)+"个格子:红")
  85.        if yellow_bili >= 0.4:
  86.            print("第二张图第"+str(3*i+j+1)+"个格子:黄")
  87.        if blue_bili >= 0.4:
  88.            print("第二张图第"+str(3*i+j+1)+"个格子:蓝")
  89.        if white_bili >= 0.4:
  90.            print("第二张图第"+str(3*i+j+1)+"个格子:白")
  91.        if orange_bili >= 0.3:
  92.            print("第二张图第"+str(3*i+j+1)+"个格子:橙")
  93.        if green_bili >= 0.4:
  94.            print("第二张图第" + str(3 * i + j + 1) + "个格子:绿")
  95. cv2.waitKey(0)
  96. cv2.destroyAllWindows()

最终效果:

开源!opencv魔方机器人视觉教程

    每一个格子都能准确识别出来,我们的视觉部分就差不多完成了,剩下的就是电控+机械部分啦~

♬..♩~ ♫. ♪..

    因为篇幅太长了,很多细节我没有细说,有空我会单独把透视变化和HSV阈值的确定和大家分享的,还有需要源文件的朋友可以在公众号【松鼠小铺子】回复“颜色识别”就可以获取啦~

来咯来咯~

有帮助的话点个赞吧~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/542851
推荐阅读
相关标签
  

闽ICP备14008679号