在公司实习的时候接到一个任务:对视频抽帧生成的图片做去重处理。所以调研了一些有关计算图像相似度的算法,目前只是用于对图片做去重处理,加以改进或许可以实现以图搜图。下面进入正题:
以上代码求出了某张图片的灰度差值,如果要计算两张图片的相似度,只需要计算出两张图片灰度差值的汉明距离: 简化色彩,缩小尺寸和比较汉明距离的代码和差值哈希算法里的一样,这里就不赘述了。 简化色彩,缩小尺寸和比较汉明距离的代码同上。 测试发现Java对图片的读取速度非常慢,所以引入了OpenCV对图片进行处理,以下为OpenCV处理图片的代码:差值哈希算法
主要流程
代码
/** * 差值哈希算法 * @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<height; i++) { for(int j=0; j<width; j++) { if(dctDate[i*height + j] >= 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<n; i++) { sb.insert(0, "0"); } } return sb.toString().toCharArray(); } /** * 离散余弦变换 * @param pix 原图像的数据矩阵 * @param n 原图像(n*n)的高或宽 * @return 变换后的矩阵数组 */ 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; } /** * 矩阵转置 * @param matrix 原矩阵 * @param n 矩阵(n*n)的高或宽 * @return 转置后的矩阵 */ private static double[][] transposingMatrix(double[][] matrix, int n) { double nMatrix[][] = new double[n][n]; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { nMatrix[i][j] = matrix[j][i]; } } return nMatrix; } /** * 求离散余弦变换的系数矩阵 * @param n n*n矩阵的大小 * @return 系数矩阵 */ private static double[][] coefficient(int n) { double[][] coeff = new double[n][n]; double sqrt = 1.0/Math.sqrt(n); for(int i=0; i<n; i++) { coeff[0][i] = sqrt; } for(int i=1; i<n; i++) { for(int j=0; j<n; j++) { coeff[i][j] = Math.sqrt(2.0/n) * Math.cos(i*Math.PI*(j+0.5)/(double)n); } } return coeff; } /** * 矩阵相乘 * @param A 矩阵A * @param B 矩阵B * @param n 矩阵的大小n*n * @return 结果矩阵 */ private static double[][] matrixMultiply(double[][] A, double[][] B, int n) { double nMatrix[][] = new double[n][n]; double t; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { t = 0; for(int k=0; k<n; k++) { t += A[i][k]*B[k][j]; } nMatrix[i][j] = t; } } return nMatrix; } /** * 求灰度图像的均值 * @param pix 图像的像素矩阵 * @param w 图像的宽 * @param h 图像的高 * @return 灰度均值 */ 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); }
附
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<height; i++) { for(int j=0; j<width; j++) { if(dctDate[i*height + j] >= 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<n; i++) { sb.insert(0, "0"); } } return sb.toString().toCharArray(); } /** 差值哈希算法 * @param src * @return */ public static char[] dHash(String src){ int width = 9; int height = 8; Mat mat = imread(src); Mat resizeMat = new Mat(); Imgproc.resize(mat,resizeMat, new Size(width, height),0,0); int[] ints = new int[width * height]; int index = 0; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { ints[index++] = gray(resizeMat.get(i, j)); } } 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 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; }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算