使用技术:Java + SpringBoot+openCV
在windows上首先需要下载opencv进行安装,先去官网:Releases - OpenCV 下载这个windows版本的安装包
下载后直接安装解压就行,然后需要,然后找到安装位置里的这个文件:
你下载的是什么版本的,这里的数字就是多少,比如我下载4.5.3版本那么这里就是453,下载4.9.0这里就显示490
这个文件是外部库,在使用opencv的时候需要用到这个文件
代码:
图片工具类:
import cn.hutool.core.io.IoUtil;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.stereotype.Component;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Base64;
import java.util.UUID;
/**
* 图片工具
*
* @author Jerry
* @date 2024/04/17
*/
@Component
public class PictureUtil {
/**
* opencv库的dll路径 todo 需要改成自己的
*/
public static final String dllPath = "J:/opencv/opencv/build/java/x64/opencv_java453.dll";
/**
* 保存临时文件的路径
*/
public static final String savePath = "D:/pngtemp";
/**
* png文件后缀
*/
public static final String pngFileSuffix = ".png";
static {
//加载
System.load(dllPath);
}
/**
* 通过opencv库获取验证码需要移动的距离 获取横坐标
*
* @param bUrlBase64 b 大图片的base64
* @param sUrlBase64 s 小图片的base64
* @return double
*/
public static double getDistanceByBase64ByOpenCv(String bUrlBase64, String sUrlBase64) {
// 读取背景图
String bFilePath = base64ToPNG(bUrlBase64);
Mat background = Imgcodecs.imread(bFilePath);
// 读取滑块图
String sFilePath = base64ToPNG(sUrlBase64);
Mat slider = Imgcodecs.imread(sFilePath);
// 使用模板匹配来找到滑块在背景图中的位置
Mat result = new Mat();
Imgproc.matchTemplate(background, slider, result, Imgproc.TM_CCOEFF_NORMED);
Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
Point matchLoc = mmr.maxLoc;
//删除临时文件
deleteFile(bFilePath, sFilePath);
return matchLoc.x;
}
/**
* 删除文件
*
* @param bFilePath b文件路径
*/
public static void deleteFile(String... bFilePath) {
for (String path : bFilePath) {
try {
new File(path).delete();
} catch (Exception ignored) {
}
}
}
/**
* 将base64转为图片
*
* @param base64String base64字符串
*/
public static String base64ToPNG(String base64String) {
//文件名
String outputFileName = savePath + "/" + UUID.randomUUID().toString() + pngFileSuffix;
ByteArrayInputStream bis = null;
OutputStream os = null;
try {
// 解码base64数据
byte[] decodedBytes = Base64.getDecoder().decode(base64String);
// 将解码后的数据转换为图像
bis = new ByteArrayInputStream(decodedBytes);
BufferedImage image = ImageIO.read(bis);
// 将图像保存为PNG文件
os = new FileOutputStream(outputFileName);
ImageIO.write(image, "png", os);
bis.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭流
IoUtil.close(bis);
IoUtil.close(os);
}
return outputFileName;
}
/**
* 只删开头
*
* @param str str
* @return {@link String}
*/
public static String substringBase64OnlyBegin(String str) {
return str.substring(str.indexOf(",") + 1);
}
public static int findSliderPosition(String bUrlBase64, String sUrlBase64) {
BufferedImage background = base64ToBufferedImage(bUrlBase64);
BufferedImage slider = base64ToBufferedImage(sUrlBase64);
;
double minDiff = Double.MAX_VALUE;
int sliderXCoordinate = 0;
for (int x = 0; x < background.getWidth() - slider.getWidth(); x++) {
double diff = 0;
for (int i = 0; i < slider.getWidth(); i++) {
for (int j = 0; j < slider.getHeight(); j++) {
int rgb1 = background.getRGB(x + i, j);
int rgb2 = slider.getRGB(i, j);
int r1 = (rgb1 >> 16) & 0xFF;
int g1 = (rgb1 >> 8) & 0xFF;
int b1 = (rgb1 & 0xFF);
int r2 = (rgb2 >> 16) & 0xFF;
int g2 = (rgb2 >> 8) & 0xFF;
int b2 = (rgb2 & 0xFF);
diff += Math.pow(r1 - r2, 2) + Math.pow(g1 - g2, 2) + Math.pow(b1 - b2, 2);
}
}
diff /= (slider.getWidth() * slider.getHeight());
if (diff < minDiff) {
minDiff = diff;
sliderXCoordinate = x;
}
}
return sliderXCoordinate;
}
/**
* base64到缓冲图像
*
* @param base64str base64str
* @return {@link BufferedImage}
*/
private static BufferedImage base64ToBufferedImage(String base64str) {
try {
byte[] imageBytes = Base64.getDecoder().decode(base64str);
ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
// 读取为BufferedImage
return ImageIO.read(bis);
} catch (Exception e) {
System.out.println("转换失败");
}
return null;
}
}
测试方法:
/**
* 测试方法
* @param args
*/
public static void main(String[] args) {
//大图片的base64
String bigbase64 = null;
//小图片的base64
String smallbase64 = null;
//返回得到的是X轴的距离(我的项目只需要X轴距离) 但是实际上在getDistanceByBase64ByOpenCv这个方法中,已经得到了X轴和Y轴的距离
double XDistance = PictureUtil.getDistanceByBase64ByOpenCv(bigbase64, smallbase64);
}
pom依赖:
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>4.5.3</version>
</dependency>
这里的pom依赖需要根据你下载的opencv版本进行调整
这个滑块识别的方法比网上的方法好用多了,识别正确率很高,3次之内必正确
如果提示缺jar包,那就需要去这里找对应的jar包引入到项目中:
具体引入方法:
按顺序操作即可引入.
如果还有任何不懂,可在评论区或者私信问我,欢迎各位一起探讨