java实现图片相似度比较(汉明距-感知哈希算法实现)

源者鬼道 2020-03-03 02:37:13
求助感兴趣的牛人,可以帮忙看一下该算法实现的相似比较,我标注的地方(代码72-88行之间)可以优化吗/毕竟4层for循环坑太深/?找到解决方案比结帖,谢谢各位先......
相似代码如下:

import java.awt.Graphics2D;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
/**
*
* 汉明距离越大表明图片差异越大,如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。
* pHash-like image hash.
* Based On: http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
*
*/
public class ImageSimilarity {
private int size = 32;
private int smallSize = 8;

private double[] c;

private ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

public ImageSimilarity() {
initCoefficients();
}

public ImageSimilarity(int size, int smallSize) {
this.size = size;
this.smallSize = smallSize;
initCoefficients();
}

private void initCoefficients() {
c = new double[size];
for(int i=1; i<size; i++) {
c[i] = 1;
}
c[0] = 1/Math.sqrt(2.0);
}

private int distance(String hash1,String hash2) {
int count = 0;
for(int i=0; i<hash1.length(); i++) {
if(hash1.charAt(i) != hash2.charAt(i)) {
count++;
}
}
return count;
}

private BufferedImage resize(BufferedImage image,int width,int height) {
BufferedImage resizedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
Graphics2D grap = resizedImage.createGraphics();
grap.drawImage(image, 0, 0, width, height, null);
grap.dispose();
return resizedImage;
}

private BufferedImage grayscale(BufferedImage image) {
colorConvert.filter(image, image);
return image;
}

private int getBlue(BufferedImage image,int x,int y) {
return (image.getRGB(x, y)) & 0xff;
}

private double[][] applyDCT(double[][] f){
int N = size;
double[][] F = new double[N][N];
//--------------------------------------------------------------------------------该过程优化
for(int u=0; u<N; u++) {
for(int v=0; v<N; v++) {
double sum = 0.0;
for(int i=0; i<N; i++) {
for(int j=0; j<N; j++) {
sum += Math
.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI)
* Math.cos(((2 * j + 1) / (2.0 * N)) * v
* Math.PI) * (f[i][j]);
}
}
sum *= ((c[u] * c[v]) / 4.0);
F[u][v] = sum;
}
}
//-------------------------------------------------------------------------------------------
return F;
}

private String getHash(String imagePath) {
BufferedImage image = null;
String hash = "";
try {
image = ImageIO.read(new File(imagePath));
} catch (IOException e) {
e.printStackTrace();
}
image = resize(image,size,size);
image = grayscale(image);

double[][] vals = new double[size][size];
for(int x=0; x<image.getWidth(); x++) {
for(int y=0; y<image.getHeight(); y++) {
vals[x][y] = getBlue(image,x,y);
}
}

// long start = System.currentTimeMillis();
double[][] dctVals = applyDCT(vals);
// System.out.println("DCT: " + (System.currentTimeMillis() - start));

double total = 0;
for(int x=0; x<smallSize; x++) {
for(int y=0; y<smallSize; y++) {
total += dctVals[x][y];
}
}
total -= dctVals[0][0];
double avg = total / (double) ((smallSize * smallSize) - 1);
for(int x=0; x<smallSize; x++) {
for(int y=0; y<smallSize; y++) {
if(x != 0 && y != 0) {
hash += (dctVals[x][y] > avg ? "1" : "0");
}
}
}
System.out.println("\"" + imagePath + "\" 's hash: " + hash);
return hash;
}

public int compartImage(String imagePath1, String imagePath2) {
return distance(
getHash(imagePath1),
getHash(imagePath2));
}
public static void main(String[] args) {
ImageSimilarity is = new ImageSimilarity();
System.out.println("Score is: "
+ is.compartImage("D://image//test/four.png", "D://image//test/fourliang.png"));

}
}
...全文
480 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
往復不息 2020-09-03
  • 打赏
  • 举报
回复
可以参考下这个 https://github.com/RobotTeam/JavaPhash
源者鬼道 2020-03-11
  • 打赏
  • 举报
回复
顶顶再..............
源者鬼道 2020-03-04
  • 打赏
  • 举报
回复
各位......静候佳音哈
预处理:读取图片 第一步,缩小尺寸。 将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。 第二步,简化色彩。 将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。 第三步,计算平均值。 计算所有64个像素的灰度平均值。 第四步,比较像素的灰度。 将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。 第五步,计算哈希值。 将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。 得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。 你可以将几张图片放在一起,也计算出他们的汉明距离对比,就可以看看两张图片是否相似。 这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。 实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。 以上内容大部分直接从阮一峰的网站上复制过来,想看原著的童鞋可以去在最上面的链接点击进去看。

50,527

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧