
3 changed files with 380 additions and 1 deletions
@ -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);
|
|||
} |
|||
|
|||
} |
@ -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…
Reference in new issue