失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > python识别魔方色块_解魔方的机器人攻略23 – 识别颜色(上)

python识别魔方色块_解魔方的机器人攻略23 – 识别颜色(上)

时间:2020-07-25 18:41:08

相关推荐

python识别魔方色块_解魔方的机器人攻略23 – 识别颜色(上)

今天看到架子上的萝卜头,已经落了很多灰尘。想起萝卜头的攻略还剩几篇迟迟没有写完。前一段时间一直在试验小爱的手机遥控器功能,从今天开始准备陆续把萝卜头的攻略补完,给博客也打扫打扫灰尘。

说起来真是很惭愧,颜色识别在萝卜头制作过程中是花费时间最多的部分。其中还有一段小插曲:

我在淘宝上买的颜色传感器,在NXT上测试时,发现只有用强光照射在魔方表面的时候,传感器才有读数。那时候在网上很难找到相关的资料,不知道是我买了次品,还是设置不当。后来我猜想传感器中心的那个透明小灯泡是光源,就擅自去电子市场买了一个LED小灯,然后把这个500块钱的传感器敲开换上。一通电,嘿,灯居然亮了,然后我就把拆下来的小灯扔到垃圾桶继续测试。结果…..这次传感器彻底废了。接下来是从垃圾桶里翻那个透明的小灯泡,非常悲剧的是那天正好吃了虾和鱼,我把整垃圾桶的虾皮鱼骨摸了两遍,才找到那个透明的小灯泡,把它洗洗干净又换上了。后来才知道,这个灯泡其实是用来读取颜色的,而不是照明的。而我买的那个颜色传感器确实是个次品,必须用灯光照射才能勉强读数。所以你们看到第一版的萝卜头,在悬臂上是带有一个照明灯的。

在此提醒一下朋友们:颜色传感器在普通的光照环境下,应该是有读数的,而且很敏感,读数会不断小幅跳动。如果你买的传感器读数一直是0或者跳动非常大,那么请尽快找奸商退换。另外,在这里感谢一下北京西觅亚公司,他们给我提供了几个测试用的颜色传感器,并且给我换了一个新的。我也因此了解了一些颜色传感器的特性。

好了,进入正题。上一篇介绍了如何在电脑和NXT之间使用蓝牙进行通讯。有了蓝牙,我们就可以把颜色传感器的读数发送给电脑,然后用电脑识别颜色后调用解魔方的算法。

1,从NXT发送颜色数据到电脑

在之前的一篇博客里,我介绍了三个函数:ReadAllSide,ReadOneSide和SendColorToPC。现在蓝牙已经调通,可以改写SendColorToPC函数用来发送数据。其中getRed()和getRawRed()等函数的说明,请参考颜色传感器的API文档

//Send colors to PC

public static void SendColorToPC(int center, int n) throws Exception

{

//get the x,y of n

int y = n % 3;

int x = (n - y) / 3;

//send to PC by bluetooth

byte[] data = new byte[9];

data[0] = (byte)center; //center表示是魔方的某一面

data[1] = (byte)x; //x 表示魔方这一面3*3的色块中,第x行的色块

data[2] = (byte)y; //y 表示魔方这一面3*3的色块中,第y列的色块

data[3] = (byte)color.getRed();

data[4] = (byte)color.getGreen();

data[5] = (byte)color.getBlue();

data[6] = (byte)(color.getRawRed() / 3);

data[7] = (byte)(color.getRawGreen() / 3);

data[8] = (byte)(color.getRawBlue() / 3);

BlueTooth.WriteBytes(data);

}

2,在PC端接受颜色数据

PC程序中的BlueToothDataReceived函数,用来响应接受到蓝牙数据的事件。我们加上下面这段函数:

else if (length == 9)

{

int i = data[0];

int j = data[1];

int k = data[2];

int r = data[3];

int g = data[4];

int b = data[5];

int rawR = data[6];

int rawG = data[7];

int rawB = data[8];

ColorItem newItem = new ColorItem(i, j, k, r, g, b, rawR, rawG, rawB);

colorDistinguish.ColorItems.Add(newItem);

DisplayMessage += newItem.ToString() + "\r\n";

Status = "成功获取数据:" + i + "," + j + "," + k;

}

其中用到了两个类 ColorItem 和 ColorItemDistinguish。这两个类的作用后面再说,总之这里把所有的颜色数据都先保存到一个阵列(Array)里,最后统一识别颜色。

3,解析颜色的方案

细心的朋友可能在API中看到了getColor()函数,我们何必要全部保存颜色后再统一分辨呢,直接读一个分辨一个不是更好?事实证明这个函数基本没什么用,红色和橙色都会解析成红色,而且环境光线变化时影响很大。还有一些朋友建议用HSV颜色模型,这种方案我也试过了,基本上也很难分辨。为什么呢?请看下面一组读数:

Red

[0,1,2]=>RGB=(23,0,0),RawRGB={45,1,8}

[0,2,2]=>RGB=(30,0,0),RawRGB={60,1,5}

[0,2,1]=>RGB=(25,0,0),RawRGB={49,3,12}

[0,2,0]=>RGB=(32,0,0),RawRGB={63,2,6}

[0,1,0]=>RGB=(22,0,0),RawRGB={43,2,11}

[0,0,0]=>RGB=(25,0,0),RawRGB={59,3,3}

[0,0,1]=>RGB=(30,0,0),RawRGB={58,5,17}

[0,0,2]=>RGB=(31,0,0),RawRGB={61,8,17}

[0,1,1]=>RGB=(31,0,0),RawRGB={62,15,22}

Orange

[2,1,2]=>RGB=(28,0,0),RawRGB={55,12,8}

[2,2,1]=>RGB=(30,0,0),RawRGB={57,14,14}

[2,0,1]=>RGB=(32,0,0),RawRGB={62,15,13}

[2,1,0]=>RGB=(32,0,0),RawRGB={63,16,12}

[2,2,2]=>RGB=(42,0,0),RawRGB={83,24,10}

[2,2,0]=>RGB=(41,0,0),RawRGB={82,24,13}

[2,0,0]=>RGB=(41,0,0),RawRGB={80,23,10}

[2,0,2]=>RGB=(39,0,0),RawRGB={76,22,13}

[2,1,1]=>RGB=(41,5,0),RawRGB={81,30,21}

这是在自然光条件下,对红色和橙色的9个色块分别读数的结果。可以看到,它们的Green和Blue分量全部是0,只有红色分量有差别。但是红色的red分量从23~32,橙色的red分量从28~42,它们中间是有重叠的。对于这些读数,HSV完全没用。

有一段时期我几乎已经绝望了,不过终于在最后让我找到了一点区别:红色的RawBlue分量基本上比RawGreen分量稍大,而橙色恰好相反。另外请对比一下[0,0,0]和[2,2,1],它们的RawBlue分量和RawGreen分量是相同的,但是仍然可以找到区别:按公式R+2*RawG-2*RawB计算,橙色的永远比红色大!

也就是说,我们单独取到一组颜色数值时,很难直接知道它是什么颜色,只有对一组数进行排序后,才能区分出不同的颜色。就像刚才这18个数,我们按照R+2*RawG-2*RawB从大到小排序,最终结果的前9个是橙色,后9个就是红色。类似的,我们还可以定义出分辨颜色的判断规则:

1,假设RGB三个值的最小值为Min,按Min从大到小排序,前9个是白色

2,剩下的颜色,按照G分量从大到小排序,前9个是黄色(有意思吧,绿色分量最大的是黄色)

3,剩下的颜色,按照B分量从大到小排序,前9个是蓝色(这个还算靠谱)

4,剩下的颜色,按照R分量从小到大排序,前9个是绿色

5,剩下的颜色,按照R+2*RawG-2*RawB从大到小排序,前9个是橙色

6,剩下的颜色全是红色

当光线从弱到强变化时,这些值基本会成比例的变大,所以这些规则依然有效。

有兴趣的朋友可以查看一组完整的颜色读数,来验证以上这些规则:http://www.diy-/rubiksolver/readcolors.txt

下一篇继续介绍这种分辨方式的具体代码实现。

如果觉得《python识别魔方色块_解魔方的机器人攻略23 – 识别颜色(上)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。