首先下载安装包
URL
安装后复制路劲opencv\build\java Java jar包,添加到自己的项目
以maven项目为例
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>4.5.1-2</version>
</dependency>
安装包的opencv_java451.dll 移动到C:\Windows\System32\opencv_java451.dll
好了开始粘贴代码
移动侦测
File tempFile = new File("E:\\temp\\", "uploadedVideo" + ".mp4");
videoFile.transferTo(tempFile);
System.out.println(tempFile.getAbsolutePath());
// 初始化视频读取
VideoCapture cap = new VideoCapture(tempFile.getAbsolutePath());
if (!cap.isOpened()) {
System.out.println("Error: Cannot open video file.");
return false;
}
Mat frame1 = new Mat();
Mat frame2 = new Mat();
Mat gray1 = new Mat();
Mat gray2 = new Mat();
// 读取第一帧
cap.read(frame1);
Imgproc.cvtColor(frame1, gray1, Imgproc.COLOR_BGR2GRAY);
// 定义矩形结构元素
Mat rectangleKernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
int frameCount = 1;
double imageArea = frame1.cols() * frame1.rows(); // 计算图像总面积(像素)
double minAreaThresholdRatio = 0.01; // 设置最小面积阈值比例(例如1%)
double minAreaThreshold = imageArea * minAreaThresholdRatio; // 计算最小面积阈值
while (true) {
// 读取下一帧
boolean ret = cap.read(frame2);
if (!ret) {
break; // 如果视频结束,跳出循环
}
Imgproc.cvtColor(frame2, gray2, Imgproc.COLOR_BGR2GRAY);
// 计算两帧的差异
Mat diff = new Mat();
Core.absdiff(gray1, gray2, diff);
// 二值化以突出差异
Mat thresh = new Mat();
Imgproc.threshold(diff, thresh, 30, 255, Imgproc.THRESH_BINARY);
Imgproc.dilate(thresh, thresh, rectangleKernel, new Point(-1, -1), 2); // 膨胀操作,使轮廓更清晰
// 找出轮廓
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(thresh, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
// 如果检测到任何轮廓,表示有移动物体,返回true
if (!contours.isEmpty()) {
MatOfPoint largestContour = contours.stream().max((c1, c2) -> Double.compare(Imgproc.contourArea(c1), Imgproc.contourArea(c2))).get();
double area = Imgproc.contourArea(largestContour);
if (area > minAreaThreshold) {
Rect boundingRect = Imgproc.boundingRect(largestContour);
Imgproc.rectangle(frame2, boundingRect, new Scalar(0, 255, 0), 2); // 用绿色矩形框出
Imgcodecs.imwrite("E:\\temp\\diff\\Thresh" + frameCount + ".jpg", thresh);
Imgcodecs.imwrite("E:\\temp\\Diff\\Frame" + frameCount + ".jpg", frame2);
// 释放资源
cap.release();
HighGui.destroyAllWindows();
return true;
}
}
frameCount++;
// 准备下一次迭代
gray1 = gray2.clone();
}
// 释放资源
cap.release();
HighGui.destroyAllWindows();
return false;
物体识别(使用配置YOLO模型)
public void MotionDetectionByAnimalImg(MultipartFile videoFile) throws IOException {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
File tempFile = new File("E:\\temp\\", "uploadedVideo" + "jpg");
videoFile.transferTo(tempFile); // Assuming this is done somewhere before
// 读取coco.names文件
String classesFile = "E:\\config\\coco.names";
// 配置YOLO模型
String modelConfiguration = "E:\\config\\yolov3.cfg";
String modelWeights = "E:\\config\\yolov3.weights";
// 输出图片路径
String outputImageFile = "E:\\temp\\cache\\output_image.jpg";
List<String> classNames = Files.readAllLines(Paths.get(classesFile));
Net net = Dnn.readNetFromDarknet(modelConfiguration, modelWeights);
net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV);
net.setPreferableTarget(Dnn.DNN_TARGET_CPU);
// 读取图片
Mat image = Imgcodecs.imread(tempFile.getAbsolutePath());
if (image.empty()) {
System.out.println("Error: Could not open image.");
return;
}
Mat blob = Dnn.blobFromImage(image, 1 / 255.0, new Size(416, 416), new Scalar(0, 0, 0), true, false);
net.setInput(blob);
List<Mat> result = new ArrayList<>();
List<String> outBlobNames = getOutputNames(net);
net.forward(result, outBlobNames);
findObjects(result, image, classNames);
// 写入图像文件
Imgcodecs.imwrite(outputImageFile, image);
// 显示图像
HighGui.imshow("Processed Image", image);
// HighGui.waitKey(0);
HighGui.destroyAllWindows();
}
private static List<String> getOutputNames(Net net) {
List<String> names = net.getLayerNames();
List<String> outNames = new ArrayList<>();
for (int unconnectedOutLayer : net.getUnconnectedOutLayers().toList()) {
outNames.add(names.get(unconnectedOutLayer - 1));
}
return outNames;
}
private static void findObjects(List<Mat> outputs, Mat frame, List<String> classNames) {
List<Integer> classIds = new ArrayList<>();
List<Float> confidences = new ArrayList<>();
List<Rect2d> boxes = new ArrayList<>();
int width = frame.width();
int height = frame.height();
for (Mat output : outputs) {
for (int i = 0; i < output.rows(); i++) {
Mat row = output.row(i);
Mat scores = row.colRange(5, output.cols());
Core.MinMaxLocResult mm = Core.minMaxLoc(scores);
float confidence = (float) mm.maxVal;
if (confidence > 0.5) {
int centerX = (int) (row.get(0, 0)[0] * width);
int centerY = (int) (row.get(0, 1)[0] * height);
int w = (int) (row.get(0, 2)[0] * width);
int h = (int) (row.get(0, 3)[0] * height);
int x = centerX - w / 2;
int y = centerY - h / 2;
classIds.add((int) mm.maxLoc.x);
confidences.add(confidence);
boxes.add(new Rect2d(x, y, w, h));
}
}
}
if (boxes.isEmpty()) {
return;
}
MatOfFloat confidencesMat = new MatOfFloat(Converters.vector_float_to_Mat(confidences));
Rect2d[] boxesArray = boxes.toArray(new Rect2d[0]);
MatOfRect2d boxesMat = new MatOfRect2d(boxesArray);
MatOfInt indices = new MatOfInt();
Dnn.NMSBoxes(boxesMat, confidencesMat, (float) 0.5f, (float) 0.4f, indices);
for (int i = 0; i < indices.rows(); i++) {
int idx = (int) indices.get(i, 0)[0];
Rect2d box = boxesArray[idx];
int classId = classIds.get(idx);
String label = classNames.get(classId) + " " + String.format("%.2f", confidences.get(idx) * 100) + "%";
Imgproc.rectangle(frame, box.tl(), box.br(), new Scalar(255, 0, 255), 2);
Imgproc.putText(frame, label, box.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.6, new Scalar(255, 0, 255), 2);
}
}
视频物体识别
// 读取coco.names文件
String classesFile = "E:\\config\\coco.names";
// 配置YOLO模型
String modelConfiguration = "E:\\config\\yolov3.cfg";
String modelWeights = "E:\\config\\yolov3.weights";
// 打开视频
VideoCapture cap = new VideoCapture("E:\\temp\\1.mp4");
// 输出视频文件路径
String outputVideoFile = "E:\\temp\\cache\\output_video.mp4";
classNames.addAll(Files.readAllLines(Paths.get(classesFile)));
Net net = Dnn.readNetFromDarknet(modelConfiguration, modelWeights);
net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV);
net.setPreferableTarget(Dnn.DNN_TARGET_CPU);
if (!cap.isOpened()) {
System.out.println("Error: Could not open video.");
return;
}
// 获取视频帧的宽度和高度
int frameWidth = (int) cap.get(Videoio.CAP_PROP_FRAME_WIDTH);
int frameHeight = (int) cap.get(Videoio.CAP_PROP_FRAME_HEIGHT);
int fps = (int) cap.get(Videoio.CAP_PROP_FPS);
VideoWriter videoWriter = new VideoWriter(outputVideoFile, VideoWriter.fourcc('X', 'V', 'I', 'D'), fps, new Size(frameWidth, frameHeight), true);
Mat frame = new Mat();
while (cap.read(frame)) {
if (frame.empty()) {
break;
}
Mat blob = Dnn.blobFromImage(frame, 1 / 255.0, new Size(inpWidth, inpHeight), new Scalar(0, 0, 0), true, false);
net.setInput(blob);
List<Mat> result = new ArrayList<>();
List<String> outBlobNames = getOutputNames(net);
net.forward(result, outBlobNames);
findObjects(result, frame);
// 写入视频
videoWriter.write(frame);
// 显示图像
HighGui.imshow("Processed Frame", frame);
// 等待按键ESC
if (HighGui.waitKey(10) == 27) {
break;
}
}
// 释放内存
cap.release();
videoWriter.release();
HighGui.destroyAllWindows();
}
private static List<String> getOutputNames(Net net) {
List<String> names = net.getLayerNames();
List<String> outNames = new ArrayList<>();
for (int unconnectedOutLayer : net.getUnconnectedOutLayers().toList()) {
outNames.add(names.get(unconnectedOutLayer - 1));
}
return outNames;
}
private static void findObjects(List<Mat> outputs, Mat frame) {
List<Integer> classIds = new ArrayList<>();
List<Float> confidences = new ArrayList<>();
List<Rect2d> boxes = new ArrayList<>();
int width = frame.width();
int height = frame.height();
for (Mat output : outputs) {
for (int i = 0; i < output.rows(); i++) {
Mat row = output.row(i);
Mat scores = row.colRange(5, output.cols());
Core.MinMaxLocResult mm = Core.minMaxLoc(scores);
float confidence = (float) mm.maxVal;
if (confidence > confThreshold) {
int centerX = (int) (row.get(0, 0)[0] * width);
int centerY = (int) (row.get(0, 1)[0] * height);
int w = (int) (row.get(0, 2)[0] * width);
int h = (int) (row.get(0, 3)[0] * height);
int x = centerX - w / 2;
int y = centerY - h / 2;
classIds.add((int) mm.maxLoc.x);
confidences.add(confidence);
boxes.add(new Rect2d(x, y, w, h));
}
}
}
if (boxes.isEmpty()) {
return;
}
MatOfFloat confidencesMat = new MatOfFloat(Converters.vector_float_to_Mat(confidences));
Rect2d[] boxesArray = boxes.toArray(new Rect2d[0]);
MatOfRect2d boxesMat = new MatOfRect2d(boxesArray);
MatOfInt indices = new MatOfInt();
Dnn.NMSBoxes(boxesMat, confidencesMat, (float) confThreshold, (float) nmsThreshold, indices);
for (int i = 0; i < indices.rows(); i++) {
int idx = (int) indices.get(i, 0)[0];
Rect2d box = boxesArray[idx];
int classId = classIds.get(idx);
String label = classNames.get(classId) + " " + String.format("%.2f", confidences.get(idx) * 100) + "%";
Imgproc.rectangle(frame, box.tl(), box.br(), new Scalar(255, 0, 255), 2);
Imgproc.putText(frame, label, box.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.6, new Scalar(255, 0, 255), 2);
}
}
模型下载地址
点击这里
YOLOv3-416 就可以了