本来想利用OpenCV的工具实现手机上的图片识别,但随着对OpenCV内容的探索,严格地说,我认为所谓的“识别”,只不过是图片的“匹配”而已。
因为计算机在图片的相似度比较上太笨了,不像人眼一看就能判断,它需要依赖大量计算的算法方可“匹配”出相似点。而且!根据相似点匹配,从而判断两张图片的内容是否一样,还需要很大的人为主观干涉。
目前研究了一下OpenCV关于图片特征匹配的基本内容,基本上实现的原理大致相同,不同的是算法在计算机上的性能表现。
要理解原理的话,可以去搜索“sift算法”,可以找到一篇小姐姐写的博客,该博客内容介绍了sift算法的原理和图像的匹配过程,详细得感人,需要掌握一定的高数和线性代数才能看得懂。数学不好的话,实际上也能大概看明白整个过程是怎么样的。
类似与sift算法的图像匹配,在计算机上实现的过程基本是: 加载图片-->找关键点-->计算关键点特征-->匹配关键点特征-->判断或者画线展示(非必须)。
其中匹配关键点是需要插入一些人为主观判断的,最后一步只是展示用,所以不一定需要。
好吧,扯了那么多,说是图片识别,连张图片都没有,没图说个j八~~好,先放一张原始的测试图:
有人会怀疑,Android用java开发,用java来做图片处理会不会很慢?其实,这里的java部分只是负责接口而已,实际上还是调用了native层的C/C++代码进行处理的,这个在上一篇关于OpenCV在Android Studio上的搭建博客里已经知道了,ctrl+右键去看源码,会发现最终到native修饰的函数就探索不下去了。
Go now~
1. 加载图片。
低版本加载图片是用Highgui这个类加载的,但高版本的opencv sdk里把读取图片的加载接口移到了Imgcodecs类去了。
Mat src=Imgcodecs.imread(imgPath);
其中参数imgPath为String类型,即图片的路径。
又或者使用Utils类加载图片
Mat src=Utils.loadResource(context, resId);
其中参数为Context,和图片id,如R.drawable.xxx。
Mat类是英文Matrix的缩写,即数学上的矩阵,用于保存图片。图片的在计算机上的处理,基本上也是矩阵的数值作各种变换处理。大学里的线性代数真的要学好呐~
2. 找关键点。
找关键点的算法有很多,如 fast, orb, mser, gftt, harris, simpleblob, brisk, akaze, sift 和 surf等
MatOfKeyPoint keyPoint=new MatOfKeyPoint();
FeatureDetector fd=FeatureDetector.create(FeatureDetector.BRISK);
fd.detect(src, keyPoint);
因为sift和surf算法有专利,所以opencv官方并没有集成,所以使用sift算法会报错。github上已有三方集成了。
每个算法找关键点不一样,导致在计算机上的性能也会不一样,最直接的表现就是时间。
fast算法,risk算法,orb算法 效果比较: