package com.lrw.opencv_test;
import com.lrw.opencv_test.utils.OpencvFilePath;
import jakarta.validation.constraints.Null;
import org.junit.jupiter.api.Test;
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;
import org.springframework.boot.test.context.SpringBootTest;
import java.net.URL;
import java.util.List;
import java.util.function.BiFunction;
@SpringBootTest
class OpencvTestApplicationTests {
// 初始化人脸探测器
static CascadeClassifier faceDetector;
static {
URL url = ClassLoader.getSystemResource("lib.opencv/opencv_java481.dll");
System.load(url.getPath());
// System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
faceDetector = new CascadeClassifier();
faceDetector.load(OpencvFilePath.FACE_DETECTOR);
}
@Test
void contextLoads() {
String imageName = "test.jpg";
Mat image = reImage(imageName,null);
//Saving the output image
String outputName = imageName;
boolean isOk = Imgcodecs.imwrite(OpencvFilePath.OUTPUT_PATH + outputName, image);
System.out.println(isOk ? "人脸识别成功!!" : "人脸识别失败!!");
}
public static Mat reImage(@Null String imageName, @Null Mat image){
//Input image
image = image==null?Imgcodecs.imread(OpencvFilePath.INPUT_PATH + imageName):image;
//Detecting faces
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);
System.out.println("识别人脸个数: " + faceDetections.toArray().length);
// 识别图片中的所以人脸并分别保存
int i = 1;
//Creating a rectangular box showing faces detected
for (Rect rect : faceDetections.toArray()) {
Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
// 进行图片裁剪
imageCut(image, "E:\\Temp\\"
+ imageName.substring(0, imageName.lastIndexOf(".")) + "_" + i +
".png", rect.x,
rect.y,
rect.width,
rect.height);
i++;
}
return image;
}
@Test
public void compareTest() {
double comparison = faceRecognitionComparison("E:\\Temp\\test_1.jpg", "E:\\Temp\\test2_1.jpg");
System.out.println("对比结果:" + comparison);
if (comparison > 0.85) {
System.out.println("人脸匹配成功");
} else {
System.out.println("人脸不匹配识别");
}
System.exit(0);
}
public static boolean compareTo(String img1, String img2) {
double comparison = faceRecognitionComparison(img1, img2);
System.out.println("对比结果:" + comparison);
if (comparison > 0.85) {
System.out.println("人脸匹配成功");
return true;
} else {
System.out.println("人脸不匹配识别");
return false;
}
}
/**
* 裁剪人脸
*
* @param image
* @param outPath 写出文件路径
* @param x 坐标X
* @param y 坐标Y
* @param width 截图宽度
* @param height 截图长度
*/
public static void imageCut(Mat image, String outPath, int x, int y, int width, int height) {
// 截取的区域
Rect rect = new Rect(x, y, width, height);
// Mat sub = new Mat(image,rect);
Mat sub = image.submat(rect);
Mat mat = new Mat();
Size size = new Size(width, height);
// 人脸进行截图并保存
Imgproc.resize(sub, mat, size);
Imgcodecs.imwrite(outPath, mat);
}
/**
* 人脸识别比对
*/
public static double faceRecognitionComparison(String image1, String image2) {
Mat mat1 = conv_Mat(image1);
Mat mat2 = conv_Mat(image2);
Mat mat3 = new Mat();
Mat mat4 = new Mat();
// 颜色范围
MatOfFloat ranges = new MatOfFloat(0f, 256f);
// 直方图大小, 越大匹配越精确 (越慢)
MatOfInt histSize = new MatOfInt(100000);
assert mat1 != null;
Imgproc.calcHist(List.of(mat1), new MatOfInt(0), new Mat(), mat3, histSize, ranges);
assert mat2 != null;
Imgproc.calcHist(List.of(mat2), new MatOfInt(0), new Mat(), mat4, histSize, ranges);
// 比较两个密集或两个稀疏直方图
return Imgproc.compareHist(mat3, mat4, Imgproc.CV_COMP_CORREL);
}
/**
* 灰度化人脸
*/
public static Mat conv_Mat(String img) {
// 读取图像
Mat mat1 = Imgcodecs.imread(img);
Mat mat2 = new Mat();
// 灰度化:将图像从一种颜色空间转换为另一种颜色空间
Imgproc.cvtColor(mat1, mat2, Imgproc.COLOR_BGR2GRAY);
// 探测人脸:检测到的对象作为矩形列表返回
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(mat1, faceDetections);
// rect中人脸图片的范围
for (Rect rect : faceDetections.toArray()) {
return new Mat(mat1, rect);
}
return null;
}
@Test
public void cameraRecognition() throws Exception {
cameraFaceRecognition();
// 终止当前运行的 Java 虚拟机。
System.exit(0);
}
public static boolean cameraLogin(String img1,String img2,BiFunction<String,String,Boolean> biFunction) {
return biFunction.apply(img1, img2);
}
/**
* 摄像头实时人脸识别
*
* @throws Exception
*/
public static void cameraFaceRecognition() throws Exception {
// 打开摄像头获取视频流,0 打开默认摄像头
VideoCapture videoCapture = new VideoCapture(0);
// 检查是否支持摄像头 true:代表摄像头可以打开 false:不可以打开
System.out.println(videoCapture.isOpened());
// 获取摄像头高度
int height = (int) videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT);
// 获取摄像头宽度
int width = (int) videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH);
if (height == 0 || width == 0) {
throw new Exception("摄像头不存在");
}
Mat video = new Mat();
int index = 0;
long startTime = System.currentTimeMillis();
if (videoCapture.isOpened()) {
while (true) {
videoCapture.read(video);
HighGui.imshow("实时人脸识别", getFace(video));
// 键盘输入
index = HighGui.waitKey(50);
// 是Esc则退出,比强制退出好
if (index == 27){
return;
}
if (System.currentTimeMillis() - startTime > 5000) {
startTime = System.currentTimeMillis();
Mat image = reImage(startTime + ".png", video);
// 写入人脸
Imgcodecs.imwrite("E:\\Temp\\" + startTime + ".png", image);
// videoCapture.release();
// return;
boolean isOk = cameraLogin("E:\\Temp\\" + startTime + "_1"+ ".png", "E:\\Temp\\1698741419596_1.png",
OpencvTestApplicationTests::compareTo);
if (isOk) {
return;
}
}
}
}
}
/**
* 从视频帧中识别人脸
*
* @param image 待处理Mat图片,即视频中的某一帧
* @return 处理后的图片
*/
public s