魔⽅机器⼈02使⽤opencv-python进⾏颜⾊识别及K-Means聚类算法
⽂章⽬录
安装opencv库
如果你是Windows系统,在anaconda搭建的环境⾥运⾏以下命令
pip install opencv-python
pip install opencv-contrib-python
关于opencv-contrib-python这个包,借⽤⼀下知乎⾥的解释
opencv-python 是只包含了主要模块的包,opencv-contrib-python包含了主要模块以及扩展模块,扩展模块主要是包含了⼀些带专利的收费算法(如shift特征检测)以及⼀些在测试的新的算法(稳定后会合并到主要模块)。
当然说的收费并不是要收你的钱,只是如果要商⽤的话要收费。没错,开源软件是可以收费的!
当然这个⼯程⽤不到opencv-contrib-python包 ⼿动狗头
如果你是Linux系统,可以执⾏以下命令:
sudo rm-rf /*
安装之前建议给pip换成国内源,或者⽤conda装也⾏,conda建议也把源换成国内的。阿⾥源中科⼤源都不错,清华源有时候很慢。安装完pip list⾥看⼀下,看看有没有
不放⼼也可以调⽤⼀下试试
安装完成。
关于在《opencv3机器视觉》⼀书中的安装⽅法,well,现在已经不需要这么⿇烦了
开始写之前,说明⼀下对opencv和python都是第⼀次接触,有什么错误与不合适之处望指正。
魔⽅状态识别
对于视觉算法,⽅法有很多,但是通⽤的视觉识别都会耗时较长的时间(⼏⼗到⼏千毫秒不等)。在这⾥我们想要把速度做到极致,同时有不失准确性和鲁棒性,于是在众多的⽅法中选择了消耗算例较⼩的⼀种。其他的众多⽅案就不介绍了,在这⾥只介绍使⽤了的⼀种。
识别⽅案思路
因为魔⽅和摄像头的位置是相对固定的,所以省略识别取边缘识别⾊块的⼀⼤坨啰啰嗦嗦的算法,直接在图像上标定每个⾊块的位置,然后进⾏颜⾊识别。
接触过视觉的童鞋应该都知道,⼤部分颜⾊识别都是在HSV坐标系下进⾏的,OpenCV储存的图像呢是BGR(注意不是RGB)格式的,所以转换成HSV来识别。关于HSV坐标的定义,可以百度或维基。
魔⽅的6个颜⾊设计的真是很闹⼼,相邻的红⾊,黄⾊和橘⾊的⾊相⾓很相近,所以容易判断出错。这⾥打算使⽤K-Means聚类算法来分类之后再判断。
最后把识别出的颜⾊转换成魔⽅的状态字符串。关于状态字符串,请参见。
识别⽅案简介
⾸先我们已经标定了54个⾊块的位置,提取了每个⾊块的HSV坐标值
第⼆步我们先判断⽩⾊的⾊块。因为⽩⾊的H值是任意的,所以我们不能把⽩⾊的H值放进聚类算法中(本⾝这个分类就没有包含所有的颜⾊信息),否则聚类会变成⼀团浆糊。提取⽩⾊的⽅法是使⽤S(饱和度)值,因为⽩⾊的饱和度是最⼩的。在这⾥⼀定要注意,为了算法的鲁棒性,我们绝不设置阈值,⽽是通过相对值来判断⽩⾊,这⼀点在后⾯举例完成后判断每类是什么颜⾊时也会⽤到。 也就是说,我们提取出S值最⼩的9个⾊块,并判断为⽩⾊。
对于剩下的45个⾊块,我们就可以使⽤聚类算法了。我们对颜⾊的H值进⾏聚类运算,把剩下的⾊块分为5类。聚类算法的实现同样可以百度或维基,待我把源码整理好挂到gitee上之后也会把链接附在这⾥。
聚类运算完成之后,记住我们还要判断结果的正确性! K-Means聚类是对初值敏感的,也就是说不好
的初值设定很可能会有不正确的结果。所以这⾥我们设置⼀种检验⽅法,具体如下
1. 是否每类有9个元素
2. 是否5个⾯中⼼位置的⾊块分别为5个不同的颜⾊
如果满⾜以上两个条件,则认为聚类运算完成;如果不满⾜,则认为聚类运算错误,重新⽣成初值并循环计算,直⾄产出正确结果运算完成。
得到正确的聚类结果之后,下⾯就需要确定每类的颜⾊。像前⾯说的,为了鲁棒性,我们不会去设定阈值,⽽是通过H值的相对⼤⼩。
这⾥⼜有⼀个需要注意的地⽅,就是红⾊的H值不是连续的。所以我们⾸先按照没个颜⾊类的聚类中⼼到绝对红⾊的绝对距离(也就是到0或180的距离)把红⾊确定出来。然后再对剩下的四类颜⾊的聚类中⼼按⼤⼩排序,就可以确定剩下四种颜⾊。
实践经验
想要让聚类算法表现出较好的效果,数据的质量⾮常重要,⽽这⼀点往往⼜是很难保证的。举个例⼦,如果使⽤多个摄像头来读取颜⾊信息,那么由于⽩平衡以及光照条件的原因,每个摄像头拍摄的
同⼀个颜⾊会是不同的颜⾊信息;甚⾄由于感光芯⽚的质量,同⼀⾯上的相近颜⾊(红⾊和橙⾊、黄⾊和⽩⾊)⾁眼也分不清。我把这种误差称为拍摄误差。事实上,拍摄误差可以⼤到从数据上完全⽆法分辨相近的颜⾊。所以这⾥就对拍摄⽅案提出了较⾼的要求。
⼀种思路是使⽤廉价的不带⽩平衡的感光芯⽚,⽐如⼀些fpv上使⽤的摄像头。这样可以解决⽩平衡带来的问题,但是并不能解决第⼆种问题。
另⼀种思路,也是我采⽤的思路,是设计⼀种较好的补光⽅案,让机器处在较好的光照条件下。我设计了⼀种⾃适应的补光⽅案,因为和本篇⽂章关系不⼤,就不赘述了。
这个问题⾃始⾄终都没有⼀个⾮常优雅的解决⽅案,似乎我使⽤的每种⽅案都是需要现场的调校,并不能做到我所预想的全环境适应的⾼鲁棒性。欢迎各位朋友在评论区交流更优的⽅案。
在图像中标定位置
这个不是很难,按照状态字符串顺序标定就好了,这⾥我写了⼀个python脚本来做这件事。
这⾥有个坑,cv2.setMouseCallback()函数中得到的x,y坐标与opencv图⽚格式⽂件索引的顺序是相反的(不知道为什么要搞这样的操作),所以坐标使⽤的时候需要反⼀下,编程的时候需要注意。
import cv2 as cv
'''
位置顺序是按照kociemba的编号排序的
'''
name ='label'
cv.namedWindow(name)
faceName =[
'U',
'R',
'F',
'D',
'L',
'B',
]
faceFile =[
'U.jpg',
'D.jpg',
'F.jpg',
'D.jpg',
'U.jpg',
'B.jpg',writelines在python中的用法
]
locationData =[]
def callback(event, x, y, flags, param):
global locationData
global img
global n
if event == cv.EVENT_LBUTTONDOWN:
print(str(n)+'clicked, please click next point')
cv.line(img,(x, y),(x, y),(255,255,255),10)
locationData.append('['+str(y)+', '+str(x)+']'+', ')
n +=1
cv.setMouseCallback(name, callback)
for i in range(6):
n =0
img = cv.imread(faceFile[i])
print(faceName[i])
while n <9:
cv.imshow(name, img)
cv.waitKey(50)
f =open('','w')
f.writelines(locationData)
f.close()
注意读取图⽚⽤的是相对位置,所以要把图⽚放到⼯程⽂件夹下。坐标结果会在⼯程的根⽂件夹下⽣成⼀个txt⽂档。你可以参考我这段代码改写,之后我也会把最终整理过的代码开源。
聚类算法
有⼀篇关于python实现K-Means聚类算法的⽂章给了我这个python⼩⽩莫⼤的启发。附上⽂章地址:
1. 相信你⼀定不会真的执⾏这⾏命令的
如果你真的执⾏了,但愿你的系统是新版本

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。