Browse Source

图片对比相似度

master
1181364@qq.com 2 years ago
parent
commit
09010a01c5
  1. 13
      yxt-supervise-monitor-biz/pom.xml
  2. 238
      yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageCompareUtil.java
  3. 130
      yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageNotWCompareUtil.java

13
yxt-supervise-monitor-biz/pom.xml

@ -59,6 +59,17 @@
<version>2.2.3</version>
</dependency>
<!-- 图片相似度-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.3.3</version>
</dependency>
</dependencies>
<build>
@ -93,4 +104,4 @@
</resources>
</build>
</project>
</project>

238
yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageCompareUtil.java

@ -0,0 +1,238 @@
package com.yxt.supervise.monitor.biz.util;
import org.bytedeco.javacpp.BytePointer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_imgcodecs.imread;
import static org.bytedeco.javacpp.opencv_imgcodecs.imwrite;
import static org.bytedeco.javacpp.opencv_imgproc.*;
/**
* @Author yzj
* @Date 2023-05-31
* @Version 1.0
*/
public class ImageCompareUtil {
private static Logger Log = LoggerFactory.getLogger(ImageCompareUtil.class);
public static void compareImage(String targetImageUrl, String baseImageUrl) {
/**
* 读取图片到数组
*/
Mat targetImage = imread(targetImageUrl);
Mat baseImage = imread(baseImageUrl);
Log.info("read image success");
/**
* 首先对比的两个图片宽度要一致否则不能对比
*/
if (targetImage.size().width() == baseImage.size().width()) {
/**
* 基本算法
* 1判断高度是否一致如果不一致需要截取到高度一致
* 2截取算法
* a因为图片有通用的顶部bar和底部bar需要先找到底部bar
* b截取长图片的部分然后和底部bar拼接就完成了图片截取
* c这里设置一个默认的宽度然后对比找到相同部分就是底部bar
*/
if (targetImage.size().height() != baseImage.size().height()) {
if (targetImage.size().height() > baseImage.size().height()) {
targetImage = dealLongImage(targetImage.clone(), baseImage.clone());
} else {
baseImage = dealLongImage(baseImage.clone(), targetImage.clone());
}
}
/**
* 进行图片差异对比
*/
Mat imageDiff = compareImage(targetImage, baseImage);
double total = 100;
double nonZeroPercent = 100 * (double) countNonZero(imageDiff) / (imageDiff.size().height() * imageDiff.size().width());
System.out.println("相似度:" + (total - nonZeroPercent));
/**
* 展示图片将标准图对比图差异图拼接成一张大图
* 其中差异图会用绿色标出差异的部分
*/
// set3ImageTo1("", targetImage, baseImage, showDiff(imageDiff, baseImage), "xxxx.jpg" );
imageDiff.release();
baseImage.release();
targetImage.release();
} else {
}
}
/**
* 2截取算法
* a因为图片有通用的顶部bar和底部bar需要先找到底部bar
* b截取长图片的部分然后和底部bar拼接就完成了图片截取
* c这里设置一个默认的宽度然后对比找到相同部分就是底部bar
*
* @return bar的高度
*/
public static int interceptBarHeight(Mat longImage, Mat shortImage) {
/**
* 设置的默认高度
*/
int imageSearchMaxHeight = 400;
Mat subImageLong = new Mat(longImage, new Rect(0, longImage.size().height() - imageSearchMaxHeight, longImage.size().width(), imageSearchMaxHeight));
Mat subImageShort = new Mat(shortImage, new Rect(0, shortImage.size().height() - imageSearchMaxHeight, shortImage.size().width(), imageSearchMaxHeight));
Mat imageDiff = compareImage(subImageLong, subImageShort);
for (int row = imageDiff.size().height() - 1; row > -1; row--) {
for (int col = 0; col < imageDiff.size().width(); col++) {
BytePointer bytePointer = imageDiff.ptr(row, col);
if (bytePointer.get(0) != 0) {
imageDiff.release();
return imageSearchMaxHeight - row;
}
}
}
return imageSearchMaxHeight;
}
/**
* 这里将两张图片作为参数传入
* 获取到共同的底部之后对长图进行截取
* 然后将顶部和底部拼接在一起就ok了
*
* @param longImage
* @param shortImage
* @return
*/
public static Mat dealLongImage(Mat longImage, Mat shortImage) {
int diffHeight = longImage.size().height() - shortImage.size().height();
int barHeight = interceptBarHeight(longImage, shortImage);
Mat dealedLongImage = new Mat(longImage, new Rect(0, 0, longImage.size().width(), shortImage.size().height() - barHeight));
Mat imageBar = new Mat(longImage, new Rect(0, longImage.size().height() - barHeight, longImage.size().width(), barHeight));
Mat dealedLongImageNew = dealedLongImage.clone();
/**
* 将头部和底部bar拼接在一起
*/
vconcat(dealedLongImage, imageBar, dealedLongImageNew);
imageBar.release();
dealedLongImage.release();
return dealedLongImageNew;
}
public static Mat compareImage(Mat targetImage, Mat baseImage) {
Mat targetImageClone = targetImage.clone();
Mat baseImageColne = baseImage.clone();
Mat imgDiff1 = targetImage.clone();
Mat imgDiff = targetImage.clone();
/**
* 首先将图片转成灰度图
*/
cvtColor(targetImage, targetImageClone, COLOR_BGR2GRAY);
cvtColor(baseImage, baseImageColne, COLOR_BGR2GRAY);
/**
* 两个矩阵相减获得差异图
*/
subtract(targetImageClone, baseImageColne, imgDiff1);
subtract(baseImageColne, targetImageClone, imgDiff);
/**
* 按比重进行叠加
*/
addWeighted(imgDiff, 1, imgDiff1, 1, 0, imgDiff);
/**
* 图片二值化大于24的为1小于24的为0
*/
threshold(imgDiff, imgDiff, 24, 255, THRESH_BINARY);
erode(imgDiff, imgDiff, new Mat());
dilate(imgDiff, imgDiff, new Mat());
return imgDiff;
}
private static void set3ImageTo1(String logTag, Mat imageSrc, Mat imageBaseSrc, Mat imageDest, String mergePicResult) {
if (imageSrc.size().width() == imageDest.size().width() && imageBaseSrc.size().height() == imageDest.size().height()) {
Mat img = imageSrc.clone();
Mat imgBase = imageBaseSrc.clone();
Mat imgDest = imageDest.clone();
Mat imgLine = new Mat(imgBase.size().height(), 1, CV_8UC3, new Scalar(0, 0, 0, 255));
Mat largeImg2 = new Mat();
Mat largeImg3 = new Mat();
Mat largeImg4 = new Mat();
Mat largeImg5 = new Mat();
/**
* 横向拼接
*/
hconcat(img, imgLine, largeImg2);
hconcat(largeImg2, imgBase, largeImg3);
hconcat(largeImg3, imgLine, largeImg4);
hconcat(largeImg4, imgDest, largeImg5);
imwrite(mergePicResult, largeImg5);
img.release();
imgBase.release();
imgDest.release();
imgLine.release();
largeImg2.release();
largeImg3.release();
largeImg4.release();
largeImg5.release();
} else {
Log.info(logTag + " pictures merge failed");
imwrite(mergePicResult, imageDest);
}
}
private static Mat showDiff(Mat imgDiff, Mat imgBase) {
MatVector rgbFrame = new MatVector();
Mat imgDest = imgBase.clone();
subtract(rgbFrame.get(2), imgDiff, rgbFrame.get(2));
subtract(rgbFrame.get(0), imgDiff, rgbFrame.get(0));
addWeighted(rgbFrame.get(1), 1, imgDiff, 1, 0, rgbFrame.get(1));
merge(rgbFrame, imgDest);
return imgDest;
}
public static void main(String[] args) {
String targetImageUrl = "C:\\Users\\Administrator\\Desktop\\5.png";
String baseImageUrl = "C:\\Users\\Administrator\\Desktop\\6.png";
compareImage(targetImageUrl, baseImageUrl);
// interceptBarHeight(targetImageUrl,baseImageUrl);
}
}

130
yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageNotWCompareUtil.java

@ -0,0 +1,130 @@
package com.yxt.supervise.monitor.biz.util;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
/**
* @Author yzj
* @Date 2023-05-31
* @Version 1.0
*/
public class ImageNotWCompareUtil {
public static String[][] getPX(String args) {
int[] rgb = new int[3];
File file = new File(args);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
}
int width = bi.getWidth();
int height = bi.getHeight();
int minx = bi.getMinX();
int miny = bi.getMinY();
String[][] list = new String[width][height];
for (int i = minx; i < width; i++) {
for (int j = miny; j < height; j++) {
int pixel = bi.getRGB(i, j);
rgb[0] = (pixel & 0xff0000) >> 16;
rgb[1] = (pixel & 0xff00) >> 8;
rgb[2] = (pixel & 0xff);
list[i][j] = rgb[0] + "," + rgb[1] + "," + rgb[2];
}
}
return list;
}
public static void compareImage(String imgPath1, String imgPath2) {
String[] images = {imgPath1, imgPath2};
if (images.length == 0) {
System.out.println("Usage >java BMPLoader ImageFile.bmp");
System.exit(0);
}
// 分析图片相似度 begin
String[][] list1 = getPX(images[0]);
String[][] list2 = getPX(images[1]);
int xiangsi = 0;
int busi = 0;
int i = 0, j = 0;
for (String[] strings : list1) {
if ((i + 1) == list1.length) {
continue;
}
for (int m = 0; m < strings.length; m++) {
try {
String[] value1 = list1[i][j].toString().split(",");
String[] value2 = list2[i][j].toString().split(",");
int k = 0;
for (int n = 0; n < value2.length; n++) {
if (Math.abs(Integer.parseInt(value1[k]) - Integer.parseInt(value2[k])) < 5) {
xiangsi++;
} else {
busi++;
}
}
} catch (RuntimeException e) {
continue;
}
j++;
}
i++;
}
list1 = getPX(images[1]);
list2 = getPX(images[0]);
i = 0;
j = 0;
for (String[] strings : list1) {
if ((i + 1) == list1.length) {
continue;
}
for (int m = 0; m < strings.length; m++) {
try {
String[] value1 = list1[i][j].toString().split(",");
String[] value2 = list2[i][j].toString().split(",");
int k = 0;
for (int n = 0; n < value2.length; n++) {
if (Math.abs(Integer.parseInt(value1[k]) - Integer.parseInt(value2[k])) < 5) {
xiangsi++;
} else {
busi++;
}
}
} catch (RuntimeException e) {
continue;
}
j++;
}
i++;
}
String baifen = "";
try {
baifen = ((Double.parseDouble(xiangsi + "") / Double.parseDouble((busi + xiangsi) + "")) + "");
baifen = baifen.substring(baifen.indexOf(".") + 1, baifen.indexOf(".") + 3);
} catch (Exception e) {
baifen = "0";
}
if (baifen.length() <= 0) {
baifen = "0";
}
if (busi == 0) {
baifen = "100";
}
System.out.println("相似像素数量:" + xiangsi + " 不相似像素数量:" + busi + " 相似率:" + Integer.parseInt(baifen) + "%");
}
public static void main(String[] args) {
ImageNotWCompareUtil.compareImage("E:\\downLoad\\宇信通\\same\\7.jpg", "E:\\downLoad\\宇信通\\same\\8.jpg");
// ImageNotWService.compareImage("E:\\downLoad\\宇信通\\same\\3.png", "E:\\downLoad\\宇信通\\same\\1.png");
}
}
Loading…
Cancel
Save