魔方机器人(二) 颜色识别
今天,就让我们来看看魔方的颜色识别是如何做到的。做图像处理的话我们可以用OpenCV(用到了颜色空间的转换RGB转HSV以及ROI区域提取),全称为Open Source Computer Vision Library,直译为“开源计算机视觉库”。我用的版本为3.0。 先来说说我做颜色识别的思路:在介绍魔方机器人的那篇博客中我们可以看到魔方在整个机器人中的相对位置是固定的,也就是说我们可以在图像确定的位置去提取颜色而不用去做轮廓识别啊什么的,这就叫所谓的定点颜色识别,但是在每个色块只提取一个像素点肯定是不行的,所以还需要做一些处理。那么问题来了,如何将图片采集到计算机中,当然是通过摄像头了,那么要用几个摄像头呢?我的建议是三个,虽然我们都知道一个摄像头同时最多能捕捉到到魔方的三个面,既然最多同时能捕捉到魔方的三个面那为什么不用两个摄像头呢?这是因为基于做颜色识别的方法,只有两个摄像头采集出来的图像做ROI不是很方便,因此我用了三个,每个摄像采集魔方的两个面。大概思路就是这样,接下来我详细和大家说说具体的实现。
- 图像采集
如下图是摄像头的放置
一个摄像头最初采集出来的图像是这样的:
根据自己的需要最终将图像切分成如下两个部分:
每个摄像头所提取的图像都像这样处理(最后的到的是六张图像)。
- 颜色识别 图像已经采集好了,接下来就是做颜色识别了。 我们可以从以上的图像看出来被切分出来的图像有些许的差别,就是有一个色块被挡住的部分在图像中的位置是不同的,于是需要写两个不同的方法分别取处理这两张图像,这里有人会问了:为什么不把其中一张图像旋转180度然后只用一个方法去处理呢?在这里我需要解释一下我为什么不这样做,原因是在你做完颜色识别之后会输出一段序列,这段序列会是你的打乱序列,还记得之前说过的打乱序列吗,这是在还原算法中会用到的,如果将其中一个图像做了旋转,那么输出的序列就会乱掉,就无法解出还原序列了,除非你在输出打乱序列之前做一些调整。 在我写的颜色识别的方法中用到了这个函数
<code class="prism language-cpp has-numbering"><span class="token function">cvtColor</span><span class="token punctuation">(</span>srcImage<span class="token punctuation">,</span> hsvImage<span class="token punctuation">,</span> COLOR_BGR2HSV<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//srcImage为原始图像,hsvImage为转换后的图像,COLOR_BGR2HSV的意思为BGR转HSV。 </span> </code>
之后
<code class="prism language-cpp has-numbering"><span class="token keyword">double</span> h<span class="token punctuation">,</span>s<span class="token punctuation">,</span>v<span class="token punctuation">;</span> Point A<span class="token punctuation">;</span> A <span class="token operator">=</span> <span class="token function">Point</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//x,y对应该像素点在图像中的位置</span> h <span class="token operator">=</span> hsvImage<span class="token punctuation">.</span>at<span class="token operator"><</span>Vec3b<span class="token operator">></span><span class="token punctuation">(</span>A<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token comment">//得到H的数值</span> s <span class="token operator">=</span> hsvImage<span class="token punctuation">.</span>at<span class="token operator"><</span>Vec3b<span class="token operator">></span><span class="token punctuation">(</span>A<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token comment">//得到S的数值</span> h <span class="token operator">=</span> hsvImage<span class="token punctuation">.</span>at<span class="token operator"><</span>Vec3b<span class="token operator">></span><span class="token punctuation">(</span>A<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token comment">//得到V的数值 </span> </code>
以上得出的只是单个像素点的H,S,V数值,我们需要取对应色块上更多的像素点H,S,V值然后计算器平均值然后再去判断其色块的颜色,具体怎么去取,用什么方式去计算均值得由自己去定义。假设我们已经得出了48个色块的s,h,v数值,之后就是进到颜色匹配的方法中,用每个色块的s,h,v范围去匹配颜色,经过颜色匹配后会输出一串序列,这个序列就是所谓的打乱序列。 各种颜色对应的hsv范围大家最好根据自己的实际情况多测试几遍之后再放到你的方法中比较好。这里我放一个我测试得出的hsv数值范围(仅供参考):
黄 | 白 | 蓝 | 绿 | 红 | 橙 | |
---|---|---|---|---|---|---|
hmin | 28 | 0 | 80 | 44 | 125 | 3 |
hmax | 44 | 180 | 124 | 77 | 180 | 28 |
smin | 43.6 | 0 | 43.6 | 43.6 | 43.6 | 43.6 |
smax | 255 | 43.5 | 255 | 255 | 255 | 255 |
vmin | 46 | 46 | 46 | 46 | 46 | 46 |
vmax | 255 | 255 | 255 | 255 | 255 | 255 |
- 打乱序列生成
在说打乱序列之前我们需要知道魔方色块颜色与字母的对应规则:魔方以中心块为黄色朝上,以中心块为红色朝前的方式放置在魔方机器人中,魔方在整个转动过程中,中心块的位置是不会发生改变的。因此制定如下颜色与字母的对应规则:黄色对应大写字母U、白色对应大写字母D、蓝色对应大写字母L、绿色对应大写字母R、红色对应大写字母F、黄色对应大写字母B。魔方还原状态所对应的序列为(UDFBLR分别对应YWROBG):
UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR 在这里我用了向量vector来存储序列,每识别出一个颜色就往vector中添加一个对应的元素,经测试,由程序所识别出来的颜色序列如下图由编号1~48顺序显示,因此将魔方展开后每个色块所对应的编号如下图:
由之前的对应来看这样顺序输出显然是不对的,因此我们需要对齐进行调整,调整后的输出顺序为:7,10,5,18,2,37,4,45,28,15,26,23,29,36,31,44,13,20,12,47,34,21,39,42,8,11,17,3,19,35,1,40,43,6,48,9,25,22,16,30,14,46,32,41,38,27,33,24。 (当然在向量vector中元素的首位置是从0开始,因此在程序里需要对每个数减一)。 下面我举个栗子来说明:
就上图识别完成之后所输出的打乱序列应为: FR UR BL FL BU FU BD DF DR LD RB LU BDL LUB LDF RFD RUF URB ULF DBR 好了,这就是机器人颜色识别的部分了。