/**
* 差值哈希算法
* @param src
* @return
*/
public char[] dHash(BufferedImage src) {
int width = 9;
int height = 8;
BufferedImage image = this.resize(src,height,width);
int[] ints = new int[width * height];
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int pixel = image.getRGB(j, i);
int gray = this.gray(pixel);
ints[index++] = gray;
}
}
StringBuilder builder = new StringBuilder();
for (int i = 0;i < height;i++){
for (int j = 0;j < width - 1;j++){
if (ints[9 * j + i] >= ints[9 * j + i + 1]){
builder.append(1);
}else {
builder.append(0);
}
}
}
return builder.toString().toCharArray();
}
/**
* 简化色彩
* @param rgb
* @return
*/
private int gray(int rgb) {
int a = rgb & 0xff000000;//将最高位(24-31)的信息(alpha通道)存储到a变量
int r = (rgb >> 16) & 0xff;//取出次高位(16-23)红色分量的信息
int g = (rgb >> 8) & 0xff;//取出中位(8-15)绿色分量的信息
int b = rgb & 0xff;//取出低位(0-7)蓝色分量的信息
rgb = (r * 77 + g * 151 + b * 28) >> 8; // NTSC luma,算出灰度值
//(int)(r * 0.3 + g * 0.59 + b * 0.11)
return a | (rgb << 16) | (rgb << 8) | rgb;//将灰度值送入各个颜色分量
}
/**
* 改变图片尺寸
* @param src 原图片
* @param height 目标高度
* @param width 目标宽度
* @return
*/
private BufferedImage resize(BufferedImage src, int height, int width) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics graphics = image.createGraphics();
graphics.drawImage(src, 0, 0, width, height, null);
return image;
}
以上代码求出了某张图片的灰度差值,如果要计算两张图片的相似度,只需要计算出两张图片灰度差值的汉明距离:
/**
* 计算汉明距离
* @param c1
* @param c2
* @return
*/
private int diff(char[] c1,char[] c2) {
int diffCount = 0;
for (int i = 0; i < c1.length; i++) {
if (c1[i] != c2[i]) {
diffCount++;
}
}
return diffCount;
}
/**
* 均值哈希算法
* @param src
* @return
*/
public char[] aHash(BufferedImage src) {
int width = 8;
int height = 8;
BufferedImage image = this.resize(src,height,width);
int total = 0;
int[] ints = new int[width * height];
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int pixel = image.getRGB(j, i);
int gray = this.gray(pixel);
ints[index++] = gray;
total = total + gray;
}
}
StringBuffer res = new StringBuffer();
int grayAvg = total / (width * height);
for (int anInt : ints) {
if (anInt >= grayAvg) {
res.append("1");
} else {
res.append("0");
}
}
return res.toString().toCharArray();
}
简化色彩,缩小尺寸和比较汉明距离的代码和差值哈希算法里的一样,这里就不赘述了。
/**
* 感知哈希算法
* @param src
* @return
*/
public char[] pHash(BufferedImage src) {
int width = 8;
int height = 8;
BufferedImage image = this.resize(src,height,width);
int[] dctDate = new int[width * height];
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int pixel = image.getRGB(j, i);
int gray = this.gray(pixel);
dctDate[index++] = gray;
}
}
dctDate = DCT.DCT(dctDate,width);
int avg = DCT.averageGray(dctDate ,width,height);
StringBuilder sb = new StringBuilder();
for(int i=0; i= avg) {
sb.append("1");
} else {
sb.append("0");
}
}
}
long result;
if(sb.charAt(0) == '0') {
result = Long.parseLong(sb.toString(), 2);
} else {
//如果第一个字符是1,则表示负数,不能直接转换成long,
result = 0x8000000000000000l ^ Long.parseLong(sb.substring(1), 2);
}
sb = new StringBuilder(Long.toHexString(result));
if(sb.length() < 16) {
int n = 16-sb.length();
for(int i=0; i
简化色彩,缩小尺寸和比较汉明距离的代码同上。
测试发现Java对图片的读取速度非常慢,所以引入了OpenCV对图片进行处理,以下为OpenCV处理图片的代码:
import com.image.DCT;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import static org.opencv.imgcodecs.Imgcodecs.imread;
public class OpenCV {
/** 均值哈希算法
* @param src 图片路径
* @return
*/
public static char[] aHash(String src){
StringBuffer res = new StringBuffer();
try {
int width = 8;
int height = 8;
Mat mat = imread(src);
Mat resizeMat = new Mat();
Imgproc.resize(mat,resizeMat, new Size(width, height),0,0);
// 将缩小后的图片转换为64级灰度(简化色彩)
int total = 0;
int[] ints = new int[64];
int index = 0;
for (int i = 0;i < height;i++){
for (int j = 0;j < width;j++){
int gray = gray(resizeMat.get(i, j));
ints[index++] = gray;
total = total + gray;
}
}
// 计算灰度平均值
int grayAvg = total / (width * height);
// 比较像素的灰度
for (int anInt : ints) {
if (anInt >= grayAvg) {
res.append("1");
} else {
res.append("0");
}
}
}catch (Exception e){
e.printStackTrace();
}
return res.toString().toCharArray();
}
/** 感知哈希算法
* @param src
* @return
*/
public static char[] pHash(String src){
int width = 8;
int height = 8;
Mat mat = imread(src);
Mat resizeMat = new Mat();
Imgproc.resize(mat,resizeMat, new Size(width, height),0,0);
int[] dctDate = new int[width * height];
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
dctDate[index++] = gray(resizeMat.get(i, j));
}
}
dctDate = DCT.DCT(dctDate,width);
int avg = DCT.averageGray(dctDate ,width,height);
StringBuilder sb = new StringBuilder();
for(int i=0; i= avg) {
sb.append("1");
} else {
sb.append("0");
}
}
}
long result;
if(sb.charAt(0) == '0') {
result = Long.parseLong(sb.toString(), 2);
} else {
//如果第一个字符是1,则表示负数,不能直接转换成long,
result = 0x8000000000000000l ^ Long.parseLong(sb.substring(1), 2);
}
sb = new StringBuilder(Long.toHexString(result));
if(sb.length() < 16) {
int n = 16-sb.length();
for(int i=0; i= ints[9 * j + i + 1]){
builder.append(1);
}else {
builder.append(0);
}
}
}
return builder.toString().toCharArray();
}
/** 简化色彩
* @param bgr
* @return
*/
private static int gray(double[] bgr) {
int rgb = (int) (bgr[2] * 77 + bgr[1] * 151 + bgr[0] * 28) >> 8;
int gray = (rgb << 16) | (rgb << 8) | rgb;
return gray;
}
/** 计算汉明距离
* @param c1
* @param c2
* @return
*/
private static int diff(char[] c1,char[] c2){
int diffCount = 0;
for (int i = 0; i < c1.length; i++) {
if (c1[i] != c2[i]) {
diffCount++;
}
}
return diffCount;
}