From 09010a01c50fc0238c293238f99207f2bfb21d57 Mon Sep 17 00:00:00 2001 From: "1181364@qq.com" Date: Wed, 31 May 2023 11:15:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=AF=B9=E6=AF=94=E7=9B=B8?= =?UTF-8?q?=E4=BC=BC=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yxt-supervise-monitor-biz/pom.xml | 13 +- .../monitor/biz/util/ImageCompareUtil.java | 238 ++++++++++++++++++ .../biz/util/ImageNotWCompareUtil.java | 130 ++++++++++ 3 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageCompareUtil.java create mode 100644 yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageNotWCompareUtil.java diff --git a/yxt-supervise-monitor-biz/pom.xml b/yxt-supervise-monitor-biz/pom.xml index 18b36a3..a2f7715 100644 --- a/yxt-supervise-monitor-biz/pom.xml +++ b/yxt-supervise-monitor-biz/pom.xml @@ -59,6 +59,17 @@ 2.2.3 + + + org.bytedeco + javacv + 1.3.3 + + + org.bytedeco + javacv-platform + 1.3.3 + @@ -93,4 +104,4 @@ - \ No newline at end of file + diff --git a/yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageCompareUtil.java b/yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageCompareUtil.java new file mode 100644 index 0000000..1b0ceca --- /dev/null +++ b/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); + } + +} diff --git a/yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageNotWCompareUtil.java b/yxt-supervise-monitor-biz/src/main/java/com/yxt/supervise/monitor/biz/util/ImageNotWCompareUtil.java new file mode 100644 index 0000000..cfa2573 --- /dev/null +++ b/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"); + } +}