图像相似度比较和检测图像中的特定物

简介: 图像相似度比较和检测图像中的特定物

对普通人而言,识别任意两张图片是否相似是件很容易的事儿。但是从计算机的角度来识别的话,需要先识别出图像的特征,然后才能进行比对。在图像识别中,颜色特征是最为常见的。每张图像都可以转化成颜色分布直方图,如果两张图片的直方图很接近,就可以认为它们很相似。这有点类似于判断文本的相似程度。


图像比较



先来比对两张图片,一张是原图另一张是经过直方图均衡化之后的图片。


image.png

原图和直方图均衡化比较.png


二者的相关性因子是-0.056,这说明两张图的相似度很低。在上一篇文章 图像直方图与直方图均衡化 中,已经解释过什么是直方图均衡化。通过直方图均衡化后,两张图片确实是不同的,可以从下图看出。


image.png

直方图均值化.png


我们来看看如何使用直方图比较。

final Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.test_hist);
        image0.setImageBitmap(bitmap);
        CV4JImage cv4jImage = new CV4JImage(bitmap);
        ImageProcessor imageProcessor = cv4jImage.convert2Gray().getProcessor();
        int[][] source = null;
        int[][] target = null;
        CalcHistogram calcHistogram = new CalcHistogram();
        int bins = 180;
        source = new int[imageProcessor.getChannels()][bins];
        calcHistogram.calcHSVHist(imageProcessor,bins,source,true);
        if (imageProcessor instanceof ByteProcessor) {
            EqualHist equalHist = new EqualHist();
            equalHist.equalize((ByteProcessor) imageProcessor);
            image1.setImageBitmap(cv4jImage.getProcessor().getImage().toBitmap());
            target = new int[imageProcessor.getChannels()][bins];
            calcHistogram.calcHSVHist(imageProcessor,bins,target,true);
        }
        CompareHist compareHist = new CompareHist();
        StringBuilder sb = new StringBuilder();
        sb.append("巴氏距离:").append(compareHist.bhattacharyya(source[0],target[0])).append("\r\n")
                .append("协方差:").append(compareHist.covariance(source[0],target[0])).append("\r\n")
                .append("相关性因子:").append(compareHist.ncc(source[0],target[0]));
        result.setText(sb.toString());


其中,CompareHist 这个类是用于直方图比较的类。


然后,再来比较两张完全一致的图片,可以看到他们的相关性因子是1.0,表示两者完全一致。


image.png

两张相同的图比较.png


最后,来比对两张完全不同的图片,可以看到它们的相关性因子是0.037,表面二者几乎没有什么相似之处。


image.png

两张完全不同的图比较.png


直方图比较是识别图像相似度的算法之一,也是最简单的算法。当然,还有很多其他的算法啦。


直方图反向投影



所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征。


image.png

反向投影的算法.png


其中,b(xi)表示在位置xi上像素对应的直方图第b(xi)个bin,直方图共m个bin,qu表示第u个bin的值。


下图是皇马的拉莫斯在2017年欧冠决赛时的图片。直方图反向投影可以根据球员球衣中的某一块区域,来查找图片中拉莫斯所穿的球衣。


image.png

直方图反向投影.png


上图是不是很酷炫?来看看是怎样使用反向投影的,需要先计算出样本的直方图,然后使用模型去寻找原图中存在的该特征。反向投影的结果包含了:以每个输入图像像素点为起点的直方图对比结果。在这里是一个单通道的浮点型图像。

Resources res = getResources();
        Bitmap bitmap1 = BitmapFactory.decodeResource(res, R.drawable.test_project_target);
        targetImage.setImageBitmap(bitmap1);
        Bitmap bitmap2 = BitmapFactory.decodeResource(res, R.drawable.test_project_sample);
        sampleImage.setImageBitmap(bitmap2);
        CV4JImage cv4jImage = new CV4JImage(bitmap1);
        ColorProcessor colorProcessor = (ColorProcessor)cv4jImage.getProcessor();
        BackProjectHist backProjectHist = new BackProjectHist();
        int w = colorProcessor.getWidth();
        int h = colorProcessor.getHeight();
        CV4JImage resultCV4JImage = new CV4JImage(w,h);
        ByteProcessor byteProcessor = (ByteProcessor)resultCV4JImage.getProcessor();
         // sample
        CV4JImage sample = new CV4JImage(bitmap2);
        ColorProcessor sampleProcessor = (ColorProcessor)sample.getProcessor();
        CalcHistogram calcHistogram = new CalcHistogram();
        int bins = 32;
        int[][] hist = new int[sampleProcessor.getChannels()][bins];
        calcHistogram.calcHSVHist(sampleProcessor,bins,hist,true);
        byte[][] source = new byte[][]{colorProcessor.getRed(),colorProcessor.getGreen(),colorProcessor.getBlue()};
        byte[][] target = new byte[3][w*h];
        Tools.rgb2hsv(source,target);
        ByteProcessor hsvByteProcessor = new ByteProcessor(target[0],w,h);
        backProjectHist.backProjection(hsvByteProcessor,byteProcessor,hist[0],new int[]{0,180});
        result.setImageBitmap(byteProcessor.getImage().toBitmap());


其中,BackProjectHist 这个类是用于直方图反向投影的类。


总结



直方图比较和直方图反向投影的算法都已经包含在cv4j中。


cv4jgloomyfish和我一起开发的图像处理库,纯java实现,目前还处于早期的版本。这次我们填完直方图的坑以后,终于把它发布到jcenter上了。


单独下载cv4j

compile 'com.cv4j:cv4j:0.1.0'


也可以下载rxcv4j,它是使用 RxJava2.x 进行的封装,如果下载该模块的话无需再下载cv4j。

compile 'com.cv4j:rxcv4j:0.1.0'


目前已经实现的功能:


image.png

cv4j.png


下周我们开始做模板匹配的算法。

相关文章
|
数据采集 Python
Python爬虫:实现爬取、下载网站数据的几种方法
Python爬虫:实现爬取、下载网站数据的几种方法
1358 1
sign check fail:check Sign and Data Fail报错攻略
错误码: com.alipay.api.AlipayApiException: sign check fail: check Sign and ​Fail            报错原因:验签失败 ,未使用正确的支付宝公钥     在新版接口的调用过程中,常常出现此报错。
5530 12
|
6月前
|
机器学习/深度学习 算法 安全
深度长文I 深度合成服务类-算法备案该怎么做?
本文详解“深度合成服务类”算法及其备案要求,涵盖定义、类型、备案流程等内容,助你全面理解合规要点。
|
机器学习/深度学习 人工智能 监控
2000 张人脸眼部检测数据集 | 标注规范、数据划分与应用场景
本 人脸眼部检测数据集(2000 张图片已划分、已标注),以中小规模的精细化标注为核心,兼顾多样性与实用性,能够满足从学术研究到工程落地的多种需求。无论是初学者进行深度学习实验,还是科研人员做算法对比,抑或企业在产品开发阶段进行原型验证,该数据集都能提供坚实的数据支撑。
|
前端开发 API vr&ar
Android开发之OpenGL绘制三维图形的流程
即将连载的系列文章将探索Android上的OpenGL开发,这是一种用于创建3D图形和动画的技术。OpenGL是跨平台的图形库,Android已集成其API。文章以2D绘图为例,解释了OpenGL的3个核心元素:GLSurfaceView(对应View)、GLSurfaceView.Renderer(类似Canvas)和GL10(类似Paint)。通过将这些结合,Android能实现3D图形渲染。文章介绍了Renderer接口的三个方法,分别对应2D绘图的构造、测量布局和绘制过程。示例代码展示了如何在布局中添加GLSurfaceView并注册渲染器。
645 1
Android开发之OpenGL绘制三维图形的流程
|
存储 SQL 分布式计算
当NameNode宕机时的应急响应与恢复策略
【8月更文挑战第31天】
615 0
|
存储 关系型数据库 MySQL
RR隔离级别在MySQL中的实现与幻读问题探讨
【10月更文挑战第3天】在数据库管理系统中,事务隔离级别是确保数据一致性和并发性能的关键要素。MySQL作为广泛使用的关系型数据库管理系统,支持多种事务隔离级别,其中可重复读(Repeatable Read,简称RR)是其默认隔离级别。本文将深入探讨RR隔离级别在MySQL中的实现原理,以及RR隔离级别下幻读问题的产生与解决方案。
544 2
|
Ubuntu Linux iOS开发
|
消息中间件 网络协议 Java
RabbitMQ消息队列的原理和实践
RabbitMQ消息队列的原理和实践
826 0
|
安全 网络协议 Java
【紧急】Log4j又发新版2.17.0,只有彻底搞懂漏洞原因,才能以不变应万变,小白也能看懂
经过一周时间的Log4j2 RCE事件的发酵,事情也变也越来越复杂和有趣,就连 Log4j 官方紧急发布了 2.15.0 版本之后没有过多久,又发声明说 2.15.0 版本也没有完全解决问题,然后进而继续发布了 2.16.0 版本。大家都以为2.16.0是最终终结版本了,没想到才过多久又爆雷,Log4j 2.17.0横空出世。
1494 0