使用Java语言 利用OpenCV,对两种图片相似度对比

package com.wzc.bms;

import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.opencv.features2d.*;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.DMatch;

/**
* @author hym
* @version 1.0.0
* @Description
* @createTime 2023年07月17日
*/
public class OpenCVImageSimilarity {

public static void main(String[] args) throws IOException {


// 加载OpenCV库

// 读取两张图像。准备比对的图片
System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 加载OpenCV库NATIVE_LIBRARY_NAME
String imageUrl1 = "https://file2023-07-14/0b653e8b-d306-4e15-8e64-4d2212a7434b.jpg"; // 网络图片的URL
String imageUrl2 = "https://file2023-07-13/98845b33-0237-45a1-a91d-714d6aba0c3c.jpg"; 

Mat image1 = readImageFromUrl(imageUrl1); // 调用方法读取网络图片
Mat image2 = readImageFromUrl(imageUrl2); 
double rdb=rdbSimilar(image1,image2);
double hash= meanHash(image1, image2);
double hist= histogram(image1, image2);
double result=(rdb+hash+hist)/ 3;
System.out.println("RDB相似度:" +rdb );
System.out.println("均值哈希算法计算相似度:"+hash);
System.out.println("图片相似度(直方图): " + hist);
System.out.println("平均值为:"+result);
/* if (image1 != null) {
// 图片读取成功,可以进行后续处理或保存
// 这里只是示例将图片保存到本地
String outputPath = "output.jpg";
Imgcodecs.imwrite(outputPath, image1);
System.out.println("图片保存成功: " + outputPath);
} else {
System.out.println("图片读取失败");
}*/
// 将图片处理成一样大

// 计算归一化交叉相关(NCC)
// double ncc = calculateNCC(image1, image2);
// System.out.println("归一化交叉相关(NCC): " + ncc);
}
private static Mat readImageFromUrl(String imageUrl) {
Mat image = null;
try {
// 使用URL类打开网络图片的输入流
URL url = new URL(imageUrl);
BufferedInputStream inputStream = new BufferedInputStream(url.openStream());

// 将输入流解码为OpenCV的Mat对象
byte[] imageData = inputStream.readAllBytes();
image = Imgcodecs.imdecode(new MatOfByte(imageData), Imgcodecs.IMREAD_COLOR);
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
static double histogram(Mat image1, Mat image2){
Imgproc.resize(image1, image1, image2.size());
Imgproc.resize(image2, image2, image1.size());

// 计算均方差(MSE)
double mse = calculateMSE(image1, image2);
// System.out.println("均方差(MSE): " + mse);

// 计算结构相似性指数(SSIM)
double ssim = calculateSSIM(image1, image2);
//System.out.println("结构相似性指数(SSIM): " + ssim);

// 计算峰值信噪比(PSNR)
double psnr = calculatePSNR(image1, image2);
// System.out.println("峰值信噪比(PSNR): " + psnr);

// 计算直方图
final double similarity = calculateHistogram(image1, image2);
// System.out.println("图片相似度(直方图): " + similarity);
return similarity;

}

// 计算均方差(MSE)
private static double calculateHistogram(Mat image1, Mat image2) {
// 计算直方图
Mat hist1 = calculateHistogram(image1);
Mat hist2 = calculateHistogram(image2);

// 计算相似度
final double similarity = Imgproc.compareHist(hist1, hist2, Imgproc.CV_COMP_CORREL);
return similarity;
}


// 计算均方差(MSE)
private static double calculateMSE(Mat image1, Mat image2) {
Mat diff = new Mat();
Core.absdiff(image1, image2, diff);
Mat squaredDiff = new Mat();
Core.multiply(diff, diff, squaredDiff);
Scalar mseScalar = Core.mean(squaredDiff);
return mseScalar.val[0];
}

// 计算结构相似性指数(SSIM)
private static double calculateSSIM(Mat image1, Mat image2) {
Mat image1Gray = new Mat();
Mat image2Gray = new Mat();
Imgproc.cvtColor(image1, image1Gray, Imgproc.COLOR_BGR2GRAY);
Imgproc.cvtColor(image2, image2Gray, Imgproc.COLOR_BGR2GRAY);
MatOfFloat ssimMat = new MatOfFloat();
Imgproc.matchTemplate(image1Gray, image2Gray, ssimMat, Imgproc.CV_COMP_CORREL);
Scalar ssimScalar = Core.mean(ssimMat);
return ssimScalar.val[0];
}

// 计算峰值信噪比(PSNR)
private static double calculatePSNR(Mat image1, Mat image2) {
Mat diff = new Mat();
Core.absdiff(image1, image2, diff);
Mat squaredDiff = new Mat();
Core.multiply(diff, diff, squaredDiff);
Scalar mseScalar = Core.mean(squaredDiff);
double mse = mseScalar.val[0];
double psnr = 10.0 * Math.log10(255.0 * 255.0 / mse);
return psnr;
}

// 计算归一化交叉相关(NCC)
// private static double calculateNCC(Mat image1, Mat image2) {
// Mat image1Gray = new Mat();
// Mat image2Gray = new Mat();
// Imgproc.cvtColor(image1, image1Gray, Imgproc.COLOR_BGR2GRAY);
// Imgproc.cvtColor(image2, image2Gray, Imgproc.COLOR_BGR2GRAY);
// MatOfInt histSize = new MatOfInt(256);
// MatOfFloat ranges = new MatOfFloat(0, 256);
// Mat hist1 = new Mat();
// Mat hist2 = new Mat();
//
// Core.normalize(hist1, hist1, 0, 1, Core.NORM_MINMAX);
// Core.normalize(hist2, hist2, 0, 1, Core.NORM_MINMAX);
// double ncc = Core.compareHist(hist1, hist2, Imgproc.CV_COMP_CORREL);
// return ncc;
// }

private static Mat calculateHistogram(Mat image) {
Mat hist = new Mat();

// 设置直方图参数
MatOfInt histSize = new MatOfInt(256);
MatOfFloat ranges = new MatOfFloat(0, 256);
MatOfInt channels = new MatOfInt(0);
List<Mat> images = new ArrayList<>();
images.add(image);

// 计算直方图
Imgproc.calcHist(images, channels, new Mat(), hist, histSize, ranges);

return hist;
}
static double rdbSimilar(Mat img1, Mat img2){
// 加载OpenCV库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

// 读取两张图片
/* Mat img1 = Imgcodecs.imread("path/to/your/image1.jpg");
Mat img2 = Imgcodecs.imread("path/to/your/image2.jpg");*/

// 创建ORB特征检测器和描述子提取器
ORB orb = ORB.create();

// 检测图像中的特征点并计算描述子
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
Mat descriptors1 = new Mat();
Mat descriptors2 = new Mat();
orb.detectAndCompute(img1, new Mat(), keypoints1, descriptors1);
orb.detectAndCompute(img2, new Mat(), keypoints2, descriptors2);

// 创建描述子匹配器
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);

// 匹配描述子
MatOfDMatch matches = new MatOfDMatch();
matcher.match(descriptors1, descriptors2, matches);

// 计算匹配结果的相似度
double maxDist = 0;
double minDist = 100;
DMatch[] matchArray = matches.toArray();
for (int i = 0; i < matchArray.length; i++) {
double dist = matchArray[i].distance;
if (dist < minDist) {
minDist = dist;
}
if (dist > maxDist) {
maxDist = dist;
}
}

// 输出相似度
double v = 1 - minDist / maxDist;
System.out.println("最小距离:" + minDist);
System.out.println("最大距离:" + maxDist);
System.out.println("RDB相似度:" +v );
return v;
}

static double meanHash(Mat img1, Mat img2){
Mat grayImg1 = new Mat();
Mat grayImg2 = new Mat();
Imgproc.cvtColor(img1, grayImg1, Imgproc.COLOR_BGR2GRAY);
Imgproc.cvtColor(img2, grayImg2, Imgproc.COLOR_BGR2GRAY);
// 缩放图像至固定大小
Size targetSize = new Size(8, 8);
Mat resizedImg1 = new Mat();
Mat resizedImg2 = new Mat();
Imgproc.resize(grayImg1, resizedImg1, targetSize);
Imgproc.resize(grayImg2, resizedImg2, targetSize);

// 计算均值哈希值
String hash1 = calculateMeanHash(resizedImg1);
String hash2 = calculateMeanHash(resizedImg2);

// 计算汉明距离并计算相似度
int hammingDistance = calculateHammingDistance(hash1, hash2);
double similarity = 1 - (double) hammingDistance / (targetSize.width * targetSize.height);

return similarity;
}

private static String calculateMeanHash(Mat image) {
double sum = 0;
int totalPixels = image.rows() * image.cols();

for (int i = 0; i < image.rows(); i++) {
for (int j = 0; j < image.cols(); j++) {
double pixelValue = image.get(i, j)[0];
sum += pixelValue;
}
}

double mean = sum / totalPixels;
StringBuilder hash = new StringBuilder();

for (int i = 0; i < image.rows(); i++) {
for (int j = 0; j < image.cols(); j++) {
double pixelValue = image.get(i, j)[0];
if (pixelValue >= mean) {
hash.append("1");
} else {
hash.append("0");
}
}
}

return hash.toString();
}

private static int calculateHammingDistance(String hash1, String hash2) {
int distance = 0;

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

return distance;
}

}
 

下载opencv官方地址:https://opencv.org/releases/
安装opencv参考地址:https://blog.csdn.net/star1210644725/article/details/131004810?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22131004810%22%2C%22source%22%3A%22star1210644725%22%7D

 

 

如果部署到inux上,需要注释掉System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 加载OpenCV库NATIVE_LIBRARY_NAME

再在类中加上静态方法:

static{

OpenCV.LoadShared();

}

posted @   舞蹈的麦  阅读(571)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示