引言

在前面两篇博客中,介绍了两种文本内容相似度比较算法,SimHash和MinHash,通过技术验证的结果来看,符合项目产品方案规划需求,接下来将把这两种算法应用于不同的场景。

而通常,我们的数据中不仅仅只有文本,也会存在图片。此前,存在图片的数据系统不会做任何处理,都只能直接交由人工处理。这样一来,工作量显然很庞大。所以,这次也调研了图片对比的几种算法,从结果来说,还是能够满足实际使用场景的。

下面介绍的三种算法本质思想都是一样的,即先计算图片的Hash,再通过海明距离表示差异,海明距离越小,则说明图片越相似。

均值Hash算法

算法过程与核心代码

  1. 缩小尺寸为8*8
public static BufferedImage thumb(BufferedImage source, int width,int height, boolean b) {// targetW,targetH分别表示目标长和宽int type = source.getType();BufferedImage target = null;double sx = (double) width / source.getWidth();double sy = (double) height / source.getHeight();if (b) {if (sx > sy) {sx = sy;width = (int) (sx * source.getWidth());} else {sy = sx;height = (int) (sy * source.getHeight());}}if (type == BufferedImage.TYPE_CUSTOM) { // handmadeColorModel cm = source.getColorModel();WritableRaster raster = cm.createCompatibleWritableRaster(width,height);boolean alphaPremultiplied = cm.isAlphaPremultiplied();target = new BufferedImage(cm, raster, alphaPremultiplied, null);} elsetarget = new BufferedImage(width, height, type);Graphics2D g = target.createGraphics();// smoother than exlax:g.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));g.dispose();return target;
}
  1. 简化色彩,转变为灰度图
public static int rgbToGray(int pixels) {// int _alpha = (pixels >> 24) & 0xFF;int _red = (pixels >> 16) & 0xFF;int _green = (pixels >> 8) & 0xFF;int _blue = (pixels) & 0xFF;return (int) (0.3 * _red + 0.59 * _green + 0.11 * _blue);
}
  1. 计算64个像素的灰度平均值
public static int average(int[] pixels) {float m = 0;for (int i = 0; i < pixels.length; ++i) {m += pixels[i];}m = m / pixels.length;return (int) m;
}
  1. 比较每个像素的灰度,与平均值进行比较。大于或等于平均值记为1;小于平均值记为0。

  2. 将上一步的结果组合在一起,就构成了一个64位的整数,即为图片的指纹。

  3. 比较hash值,计算海明距离。

/*** 计算"海明距离"(Hamming distance)。* 如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。** @param sourceHashCode 源hashCode* @param hashCode       与之比较的hashCode*/
public static int hammingDistance(String sourceHashCode, String hashCode) {int difference = 0;int len = sourceHashCode.length();for (int i = 0; i < len; i++) {if (sourceHashCode.charAt(i) != hashCode.charAt(i)) {difference++;}}return difference;
}

感知Hash算法

算法过程与核心代码

  1. 缩小尺寸为8*8
private static BufferedImage resize(BufferedImage image, int width, int height) {BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);Graphics2D g = resizedImage.createGraphics();g.drawImage(image, 0, 0, width, height, null);g.dispose();return resizedImage;
}
  1. 简化色彩,转变为灰度图
private static int gray(int rgb) {//将最高位(24-31)的信息(alpha通道)存储到a变量int a = rgb & 0xff000000;//取出次高位(16-23)红色分量的信息int r = (rgb >> 16) & 0xff;//取出中位(8-15)绿色分量的信息int g = (rgb >> 8) & 0xff;//取出低位(0-7)蓝色分量的信息int b = rgb & 0xff;// NTSC luma,算出灰度值rgb = (r * 77 + g * 151 + b * 28) >> 8;//(int)(r * 0.3 + g * 0.59 + b * 0.11)//将灰度值送入各个颜色分量return a | (rgb << 16) | (rgb << 8) | rgb;
}
  1. 计算DCT(离散余弦变换),得到32*32的系数矩阵。缩小DCT,只保留左上角的8乘8的矩阵
public static int[] DCT(int[] pix, int n) {double[][] iMatrix = new double[n][n];for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {iMatrix[i][j] = (double) (pix[i * n + j]);}}double[][] quotient = coefficient(n);    //求系数矩阵double[][] quotientT = transposingMatrix(quotient, n);    //转置系数矩阵double[][] temp = matrixMultiply(quotient, iMatrix, n);iMatrix = matrixMultiply(temp, quotientT, n);int newpix[] = new int[n * n];for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {newpix[i * n + j] = (int) iMatrix[i][j];}}return newpix;
}
  1. 计算DCT的平均值
public static int averageGray(int[] pix, int w, int h) {int sum = 0;for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {sum = sum + pix[i * w + j];}}return sum / (w * h);
}
  1. 计算哈希值

  2. 比较hash值,计算海明距离

差异值Hash算法

算法过程与核心代码

  1. 图片缩放为9*8大小

  2. 将图片灰度化

  3. 差异值计算(每行相邻像素的差值,这样会生成8*8的差值,前一个像素大于后一个像素则为1,否则为0)

  4. 生成哈希值

  5. 比较hash值,计算海明距离

public class ImageDHash {/*** 计算dHash方法** @param file 文件* @return hash*/public static String getDHash(File file) {//读取文件BufferedImage srcImage;try {srcImage = ImageIO.read(file);} catch (IOException e) {e.printStackTrace();return null;}//文件转成9*8像素,为算法比较通用的长宽BufferedImage buffImg = new BufferedImage(9, 8, BufferedImage.TYPE_INT_RGB);buffImg.getGraphics().drawImage(srcImage.getScaledInstance(9, 8, Image.SCALE_SMOOTH), 0, 0, null);int width = buffImg.getWidth();int height = buffImg.getHeight();int[][] grayPix = new int[width][height];StringBuffer figure = new StringBuffer();for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {//图片灰度化int rgb = buffImg.getRGB(x, y);int r = rgb >> 16 & 0xff;int g = rgb >> 8 & 0xff;int b = rgb & 0xff;int gray = (r * 30 + g * 59 + b * 11) / 100;grayPix[x][y] = gray;//开始计算dHash 总共有9*8像素 每行相对有8个差异值 总共有 8*8=64 个if (x != 0) {long bit = grayPix[x - 1][y] > grayPix[x][y] ? 1 : 0;figure.append(bit);}}}return figure.toString();}/*** 计算海明距离* <p>* 原本用于编码的检错和纠错的一个算法* 现在拿来计算相似度,如果差异值小于一定阈值则相似,一般经验值小于5为同一张图片** @param str1* @param str2* @return 距离*/private static long getHammingDistance(String str1, String str2) {int distance;if (str1 == null || str2 == null || str1.length() != str2.length()) {distance = -1;} else {distance = 0;for (int i = 0; i < str1.length(); i++) {if (str1.charAt(i) != str2.charAt(i)) {distance++;}}}return distance;}
}

总结

相比感知Hash算法,差异值Hash算法的速度要快的多,相比平均值Hash算法,差异值Hash算法在效率几乎相同的情况下的效果要更好,它是基于渐变实现的。所以在项目中选择了最后一种差异值Hash算法,结果也是与预期一致。

比较图片相似度算法介绍与应用(Java版)相关推荐

  1. java 堆排序算法_堆排序算法的讲解及Java版实现

    这篇文章主要介绍了堆排序算法的讲解及Java版实现,堆排序基于堆这种数据结构,在本文中对堆的概念也有补充介绍,需要的朋友可以参考下 堆是数据结构中的一种重要结构,了解了"堆"的概念 ...

  2. 算法--猫扑素数--java版

    算法–猫扑素数–java版 简介 猫扑素数: 形如以 2 开头, 之后跟任意多个 3 的十进制整数如果是个素数, 则它是猫扑素数. 如 2, 23, 233, 2333, 23333 都是猫扑素数, ...

  3. 利用 JS 实现多种图片相似度算法

    编者按:本文来自 Jrain-前端玩具盆 思否专栏,由作者 jrainlau 授权奇舞周刊转载. 在搜索领域,早已出现了"查找相似图片/相似商品"的相关功能,如 Google 搜图 ...

  4. 数据结构与算法之排序(Java版)

    文章目录 时间复杂度 冒泡排序 算法介绍: 代码实现: 时间性能测试:9s 9355ms 选择排序 思路解析: 代码实现: selectSort方法 Main方法 时间性能测试:3s 2650ms 插 ...

  5. 分布式主键解决方案----Twitter 雪花算法的原理(Java 版)

    SnowFlake 雪花算法 对于分布式系统环境,主键ID的设计很关键,什么自增intID那些是绝对不用的,比较早的时候,大部分系统都用UUID/GUID来作为主键,优点是方便又能解决问题,缺点是插入 ...

  6. python 图片相似度算法比较_python 比较2张图片的相似度的方法示例

    本文介绍了python 比较2张图片的相似度的方法示例,分享给大家,具体如下: #!/usr/bin/python # -*- coding: UTF-8 -*- import cv2 import ...

  7. 图片相似度算法比较一般流程

    1. 缩放图片 将需要处理的图片所放到指定尺寸,缩放后图片大小由图片的信息量和复杂度决定.譬如,一些简单的图标之类图像包含的信息量少,复杂度低,可以缩放小一点.风景等复杂场景信息量大,复杂度高就不能缩 ...

  8. C#对比图片相似度算法

    参考Neal Krawetz博士的这篇文章, 实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格 ...

  9. 一致性哈希算法介绍,及java实现

    https://www.cnblogs.com/hupengcool/p/3659016.html 应用场景 在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括: 轮循算法(Round Rob ...

最新文章

  1. 面试时与人事交谈时间_如何与您的技术负责人交谈并解决通讯故障
  2. java迭代器的使用场景_集合遍历利器 -- 迭代器模式 介绍 使用场景案例 优缺点及程序演示...
  3. MATLAB的imtransform()函数作图像线性平移时如果要体现效果要加上目标Size限制
  4. LeetCode19删除链表的倒数第N个节点20有效的括号
  5. ext grid 重新布局_如何让你的 CSS Grid 布局有良好的可访问性
  6. Git学习总结(一)
  7. Jquery的DOM
  8. python观察日志(part6)--不可变的元祖
  9. 团队作业3——需求改进系统设计
  10. pythonweb服务器部署iis_IIS部署python Web(FLASK试例)
  11. Query框架学习第九天:jQuery工具函数介绍与使用
  12. 基于Text-CNN模型的中文文本分类实战
  13. Android开机自动运行APP——BroadcastReceiver
  14. # 安卓手机启动黑阈服务
  15. FPGA学习篇之计数器
  16. har2case接口脚本必备工具
  17. python人脸特征提取_Python实现识别人脸特征并打印出来
  18. 光滑噪声数据常用的方法_整理一份详细的数据预处理方法
  19. 如何选择合适的无线网桥
  20. 十大券商:“推土机行情”再现

热门文章

  1. 常见的排序算法及java实现
  2. 通达信自动交易系统接口安装方式
  3. FG96-8CH 搭配Realsense D457 在Jetson AGX Orin/Xavier上的展示
  4. HTML5期末大作业:在线电影网站设计——网上电影票预订网站 HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设计源码
  5. Android ps进程命令
  6. 机架式服务器要不要装系统,机架式服务器安装方法
  7. Elasticsearch+IK+pinyin自定义分词器
  8. iPhone 6弧角边 如放大版iPod touch
  9. linux+字体设置推荐,linux字体设置从入门到精通(入门级)
  10. 惠普HP Laser NS MFP 1005c 打印机驱动