本文方向

就是想通过一张照片检测魔方是否还原,整个CSDN上找不到方法,经过探索,找到了一个还算靠谱的方法,在这里介绍给大家,同时也讲讲我当时的心路历程,测试过但最终放弃的一些方法,如果网友们有改进方案,欢迎评论,最后的方法比较鲁棒,但是背景过于复杂时误差比较大,这是由于HSV颜色空间本身具有不稳定性,比如红色和棕色的区域在一起,而我们有的时候(测试图片)的背景板就是棕色的,通过颜色空间并无法区别。

本文操作环境:win10+opencv3.4.1+vs2017,语言:C++

原图如下(当然我测试了五十张)效果不一

前后思路

1.计数色块数量

首先,我想到的是数不同颜色色块的个数,这样做首先是要提取色块,实际上要做到比较稳定的提取色块极其的困难,尤其是对于有些测试图片的侧面很小,很多颜色的色块很小,容易两块相邻的混在一起,干扰计数,其次,我采用先针对一个颜色,提取所有色块并用findcontours()函数找到轮廓,然后用sizeof(),得出轮廓的数量,如果照片范围内的轮廓数量等于9或等于0,则测试下一种颜色,知道一种颜色色块数量属于0~9,则可以判断未还原,如果全是0或9,则还原。
思路是没什么问题,测试过程却不是很顺利,首先是色块的提取,有两种方案,一是在原图取阈值大约150左右的定阈值(自适应阈值试过效果很差),这个值是我创建滑动条对多张图片测试得到的,在得到的二值图中提取轮廓,用函数中的参量选RETR_TREE,拿到魔方的大轮廓,然后把大轮廓用矩形(不用旋转矩形)框出来作为感兴趣区域,在原图对ROI进行分析,这样基本可以去除背景只对魔方分析,在ROI内用inrange函数(这个函数是所有方法的核心),可以直接把对应的颜色提取出来得到二值图,然后进行findcontours并计数轮廓
各个颜色的范围测试如下,橙色红色经常混,但蓝绿黄很清晰

inRange(imgHSV, Scalar(90, 43,46 ), Scalar(125, 255, 255), imgThresholded1);                                  /*判断九个块是否有 **蓝色**         */
inRange(imgHSV, Scalar(45, 40, 40), Scalar(95, 255, 255), imgThresholded2);
/*判断九个块是否有 **绿色**      */
inRange(imgHSV, Scalar(0, 0, 100), Scalar(180, 30, 255), imgThresholded3);
/*判断九个块是否有 **白色**     */
inRange(imgHSV, Scalar(140, 40, 40), Scalar(180, 255, 255), imgThresholded4);
/*判断九个块是否有 **红色**       */
inRange(imgHSV, Scalar(0, 40, 40), Scalar(20, 255, 255), imgThresholded5);
/*判断九个块是否有 **橙色**        */
inRange(imgHSV, Scalar(20, 40, 40), Scalar(30, 255, 255), imgThresholded6);
/*判断九个块是否有 **黄色**        */ 

还是有很大的问题,白色之前不能取阈值,因为会直接被过滤掉,另外就是很小的侧面色块容易混合的问题,如下图

这种图虽然能把颜色提取出来,但是黄色轮廓却画不出九个
如下图会被画成三个,而且各种形态学的方案也测过了,无论是膨胀腐蚀,始终不能得到清晰的轮廓,因此这个方案最终被废弃,这里只给大家提供一个思路,有想法的朋友可以试着完善

2.计算色块面积

第二个思路是计算不同色块的面积,
因为如果魔方还原了,那么肯定魔方的有颜色区域面积就是由3个色块的总面积构成的,否则魔方的任意3个色块总面积之和应该不会超过80%总面积,
这个算法,要把全部的色块面积提取出来,我使用的掩膜操作加inrange函数,这个方法是我在走投无路是发现的绝妙方法,因为无论怎么取阈值都无法完美的去除不同色块中间的黑色背景线条,于是,我用上一种方法得到的ROI区域中先用inrange取出颜色,然后把这个颜色二值图作为掩膜贴到原图,这个操作比较类似图像与操作bitwise_and,但我用的是copy to函数,特别特别完美拿到色块函数操作如下

Mat getMat()
{Mat dst, img2, img_gray, img_binary;                      //img2为结果图,img1为原图,img是接下来要经过二值化处理的图             namedWindow("原图");Mat img = imread("D:\\图片\\20.jpg");Mat img1 = imread("D:\\图片\\20.jpg");cvtColor(img, img, CV_BGR2HSV);cvtColor(img, img, CV_BGR2GRAY);                               //对img进行一系列处理二值化GaussianBlur(img, img, Size(5, 5), 0, 0);threshold(img, img, 140, 255, THRESH_BINARY);medianBlur(img, img, 3);imshow("j", img);img1.copyTo(img2, img);                                        //核心掩膜处理imshow("原图", img1);imshow("结果图", img2);return img2;
}

拿到的图如下

就可以开始提取对应颜色的轮廓,然后用contourarea()函数计算每个轮廓面积之和并累加,,理论上得解。
但是,实际上问题比第一种方法更严重,因为非常依赖魔方摆放的角度,如果确实只有一个面还原了但是在侧面露出面积极小,就会占到很小面积而导致测试结果错误。
所以这个方法也被废弃掉了,同样欢迎评论。

最终方案

偶然想到的方案成为了光照不变性和旋转不变性都最好的方案

如果魔方被还原,那么相机的视角里,最多存在三种颜色,也可能是两种或一种,
但是如果是没还原的,一定是超过三种颜色的,因此,我们只要数颜色的个数就行了,
同样,我们用上个方法拿到的getmat()返回的图片中再次用inrange找每个颜色的对应的二值图,没有该颜色就是纯黑,如下图

然后对图片的每个像素点进行遍历,如果为出现了白色说明这种颜色出现了,就break并使颜色计数器加一,(有一个坑要提醒大家,我们的计算机在遍历图片像素是很快的,瞬间完成,但是如果你在每一个像素点的循环中都打印一次这个点是黑或白,就会很慢,最开始我为了测试在循环中加入打印,一张图遍历了2分钟,我还以为是性能问题,删了打印瞬间完成),这个遍历的代码如下

int panduan(Mat imgThresholded)
{int colornum = 0, false1 = 0,green=0;for (int y = 0; y <  imgThresholded.rows; y++){if (false1 == 1) { break; }for (int x = 0; x <  imgThresholded.cols; x++){if ( imgThresholded.at<uchar>(y, x)==255){false1 = 1; green = 1; cout << "有色" << endl; break;}else{//cout << "其他";如果不加注释,就会每个黑色像素点打印一个“其他”,从而遍历很长时间continue;}}}return green;
}

到这里,就基本可以完成检测了,这个方法的噪声是去除得很干净的,所以我才敢用遍历像素点,因为最开始选定ROI时就已经排除了背景板上的噪声,用copyto获得掩膜后的图时更是排除了有色区域外的噪声,而且我的getmat()函数中也有开操作来消除小噪声,所以最后的inrange后得到的是图片中纯净的颜色的二值图,
(重点:另一个坑:如果你用的是1080p相机拍的照片,会因为太大无法处理,这时候我在主函数中把用getmat()得到的图片用resize()函数进行缩小,但是要告诉大家,最后得到的图片不能太小,否则小色块会被滤除,建议缩小三倍,具体你们可以自己试试,毕竟不同相机也不一样),resize函数使用如下

imgOriginal = getMat();resize(imgOriginal, imgOriginal_quarter, Size(imgOriginal.cols / 3, imgOriginal.rows / 3), 0, 0, INTER_AREA);

这个算法剩下的问题就是由于HSV颜色空间本身的不稳定性,因为红色和橙色的颜色特别相近,所以在光照的影响下经常会混,但这是无法解决的,方法本身的弊端,但是可以告诉大家,蓝色和绿色的检测十分准确 ,从不出错,所以大家可以简化程序只对蓝色或绿色进行测试,(比如还原的魔方我把蓝色扣在下面,如果识别出了蓝色则一定未还原 ,等等的简化方案),效果稳定。
检测蓝色结果

另外的弊端:如果环境过于复杂,会在最开始出现问题,就是找到魔方的轮廓矩形ROI,如果环境复杂会可能有几个轮廓或无法准确框出魔方,那么后面的处理自然就无法锁定魔方上的颜色,这些我目前还没有想出什么稳定的方案,正在努力看轮廓和边缘的检测方向的博客,也想试试可不可以用canny边缘检测来确定魔方的边缘,从而锁定魔方,当然设想还有好多,欢迎大家评论。

源代码

关于源代码,大家可以到我的GitHub上去下载,但是我做这个项目是为了一个夏令营比赛,因此我为了稳定的效果只检测了蓝色,对别的颜色检测方法是一样的,大家自己改一下inrange就行,范围上面是我测得,不一定准,大家可以根据实际环境创建一个createTrackbar()自己调一下,记的点赞哦

我的GitHub地址:https://github.com/freddy-hu/cube_color_detect,记得点赞哦

感觉传统视觉有点捞了,TensorFlow来做的话,应该没这么多问题。。。

根据HSV颜色空间识别魔方是否还原相关推荐

  1. Python+Opencv简易车牌识别(二):形态学运算,HSV颜色空间筛选与图像分割

    注:这是依然一个简单的车牌识别demo 1.前言 在上一篇Python+Opencv简易车牌识别(一):基于HSV颜色空间的图像分割中,我们讲了如何仅基于颜色来进行简单粗暴的车牌分割.今天我们考虑对图 ...

  2. opencv颜色识别python_opencv使用HSV颜色空间实现颜色识别

    一.颜色空间介绍 RGB 颜色空间是大家最熟悉的颜色空间,即三基色空间,任何一种颜色都可以由该三种 颜色混合而成.然而一般对颜色空间的图像进行有效处理都是在 HSV 空间进行的,HSV(色调 Hue, ...

  3. opencv学习笔记二十一:使用HSV颜色空间实现颜色识别

    一.颜色空间介绍        RGB 颜色空间是大家最熟悉的颜色空间,即三基色空间,任何一种颜色都可以由该三种 颜色混合而成.然而一般对颜色空间的图像进行有效处理都是在 HSV 空间进行的,HSV( ...

  4. opencv-python识别魔方特定颜色方块,并输出各方块中心坐标

    先叠个甲(作者寒假才开始自学opencv,做题练手,还不是很熟练,如果有不正确或者有更好的方法,欢迎在评论区指出) 题目:从网上寻找任一魔方图片,识别其中白色色块,描绘并输出其中所有白色色块的中心点坐 ...

  5. python+opencv多进程实现识别魔方颜色,通过kociemba算法得出算法字符串并画图(附毕设完整视频)

    完整毕设成果视频如下: 本科毕业设计转魔方(声音略大) python+opencv本科毕业设计转魔方(声音略大) 上一篇博客已经给大家讲了鼠标hsv获取魔方颜色阈值方法,具体见 python+open ...

  6. 三阶魔方自动还原 vc实现

    魔方自动求解程序一般有两种方法,一种是按照人还原魔方的步骤,一步步来,另外一种是使用数学方法,魔方自有一套复杂的数学理论,其中较著名的是两阶段算法(压缩文件中的cube430.exe使用的就是数学方法 ...

  7. RGB颜色空间、色调、饱和度、亮度、HSV颜色空间详解

    一.概述 本文章会详细的介绍RGB颜色空间与RGB三色中色调.饱和度.亮度之间的关系,最后会介绍HSV颜色空间! 一.RGB颜色空间 1. 起源 RGB三原色起源于上世纪初1809年Thomas Yo ...

  8. 【OpenCV】HSV颜色识别-HSV基本颜色分量范围

    出处:百度文库 一般对颜色空间的图像进行有效处理都是在HSV空间进行的,然后对于基本色中对应的HSV分量需要给定一个严格的范围,下面是通过实验计算的模糊范围(准确的范围在网上都没有给出). H:  0 ...

  9. OpenCV通过HSV颜色空间过滤图片及目标检测颜色空间范围确定

    在目标检测中,我们可以通过卷积网络进行目标检测,但实际上,卷积网络并不能完全正确.所以,我们可以通过其它方式进行筛选,比如颜色空间 参考: Image Segmentation Using Color ...

最新文章

  1. 拒绝遗忘:高效的动态规划算法
  2. Android前沿技术
  3. Android Studio调试时遇见Install Repository and sync project的问题
  4. Cloud一分钟 | 蚂蚁金服估值超万亿;Google大举进军游戏市场
  5. UVA - 227 Puzzle
  6. 自定义字体 (暂不支持中文)
  7. spring-第十九篇AOP面向切面编程之增强处理的优先级
  8. JAVA 相关书籍推荐(全)
  9. XMPP即时通讯协议使用(十)——好友关系状态
  10. Windows使用WakeOnLan配置【较详细】
  11. Axure 进阶教程
  12. note2便携式WLAN热点开启后没连接时自动关闭时长在哪设置
  13. vue实现:带关键字跳转企查查并搜索关键字对应的企业
  14. 我的世界服务器怎么开启坐标显示,坐标 - Minecraft Wiki,最详细的官方我的世界百科...
  15. Oracle针对EMP表的练习题(很有用,值得收藏)
  16. 使用SpringBoot一小时快速搭建一个简单后台管理(后端篇)
  17. 【苹果家庭相册群发】CSR邮箱必须与证书所属的AppID相同
  18. 免费的网络学习工具【eNSP】
  19. 百度开放云 视频转码服务
  20. java编写车类_用Java程序创建一个汽车接口,接口中要定义汽车应有的属性和行为,随后编写多个汽车接口的实现类,...

热门文章

  1. ol-地图上添加图标
  2. 常用英雄胜率怎么刷_王者荣耀英雄胜率怎么刷 王者荣耀刷英雄胜率的方法
  3. Wind安装程序出现x80070652错误问题
  4. python中时间加一个小时
  5. 游戏音乐怎样达到阴阳平衡?
  6. 关于怎么学习好一门技术一门语言
  7. 旅游评论情感分析(2)---前期调查总结
  8. NX/UG二次开发创建曲面偏置体
  9. 【文档留存】泛微OA POC
  10. jQuery特效,网站模板,商城模板,网页特效各种前端源码免费下载