YOLOv26作为新一代轻量化检测模型,相比YOLOv8推理速度提升22%、参数量减少15%,非常适合Java端快速落地。本文针对零基础Java开发者,打造“30分钟闭环”实战教程——从环境搭建、模型准备,到核心调用、结果可视化,全程无复杂深度学习概念,只需Java基础,跟着步骤做就能在30分钟内跑通第一个Java+YOLOv26检测案例,还能直观看到带检测框的可视化结果。

整体规划(30分钟)

环节耗时核心目标
环境搭建10分钟配置JDK/Maven,引入核心依赖
YOLOv26模型准备5分钟获取可直接调用的ONNX格式模型
核心代码实现10分钟完成预处理、推理、结果解析
结果可视化5分钟绘制检测框,保存/展示检测结果

步骤1:环境快速搭建(10分钟)

1.1 前置检查(2分钟)

确保本地已安装以下工具(无则快速安装):

  • JDK 11+:打开命令行执行 java -version,输出java version "11.0.x"即可;

  • Maven 3.6+:执行 mvn -v,输出Apache Maven 3.6.x即可。

新手安装提示:Windows可直接下载JDK/Maven压缩包,配置JAVA_HOME/MAVEN_HOME环境变量;Linux执行apt install openjdk-11-jdk maven一键安装。

1.2 创建Maven项目(3分钟)

  1. 新建Maven项目(IDEA/Eclipse均可),GroupId填com.yolo.demo,ArtifactId填yolov26-java-demo

  2. 替换pom.xml内容(核心依赖已适配Windows/Linux,直接复制):


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 d">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yolo.demo</groupId>
    <artifactId>yolov26-java-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 微软仓库(ONNX Runtime依赖) -->
    <repositories>
        <repository>
            <id>microsoft-maven</id>
            <url></url>
        </repository>
        <repository>
            <id>aliyun</id>
            <url></url>
        </repository>
    </repositories>

    <properties>
        <java.version>11</java.version>
        <onnxruntime.version>1.18.0</onnxruntime.version>
        <javacv.version>1.5.11</javacv.version>
    </properties>

    <dependencies>
        <!-- 核心依赖:ONNX Runtime(Windows x64,Linux替换为linux-x86_64/linux-arm64) -->
        <dependency>
            <groupId>com.microsoft.onnxruntime</groupId>
            <artifactId>onnxruntime</artifactId>
            <version>${onnxruntime.version}</version>
            <classifier>windows-x86_64</classifier>
        </dependency>

        <!-- JavaCV:图像预处理+可视化(OpenCV/FFmpeg) -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>${javacv.version}</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>opencv-platform</artifactId>
            <version>4.8.0-${javacv.version}</version>
        </dependency>

        <!-- 工具类:简化代码 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

1.3 依赖下载(5分钟)

  • 点击IDEA的Load Maven Changes,或执行mvn clean install

  • 关键适配:若部署到Linux,将onnxruntimeclassifier改为linux-x86_64(x86服务器)/linux-arm64(树莓派);

  • 下载慢解决:确保pom.xml已配置阿里云镜像,耐心等待依赖下载完成(首次下载约3-5分钟)。

步骤2:YOLOv26模型准备(5分钟)

2.1 获取ONNX模型(3分钟)

YOLOv26官方提供预训练模型,需转换为ONNX格式(新手直接用以下简化方式):

  1. 临时安装Python(仅用于导出模型,无需深入学习):安装Python 3.8+,执行pip install ultralytics

  2. 新建export_yolov26.py,运行导出ONNX模型:


# export_yolov26.py(仅需运行一次)
from ultralytics import YOLO

# 加载YOLOv26n轻量化模型(适合Java端)
model = YOLO('yolov26n.pt')
# 导出ONNX格式(简化+适配Java)
model.export(format='onnx', imgsz=640, simplify=True, opset=12)
  1. 导出完成后,在项目根目录新建models文件夹,将生成的yolov26n.onnx复制到models目录。

2.2 验证模型(2分钟)

确认models/yolov26n.onnx文件存在(大小约4MB),模型准备完成。

步骤3:核心代码实现(10分钟)

3.1 项目结构

确保项目结构如下(新手直接按此创建包和类):


yolov26-java-demo/
├── models/
│   └── yolov26n.onnx
├── src/
│   └── main/
│       └── java/
│           └── com/
│               └── yolo/
│                   └── demo/
│                       ├── config/YOLOConfig.java       // 配置类
│                       ├── util/PreprocessUtils.java   // 预处理工具
│                       ├── engine/YOLOv26Engine.java   // 推理引擎
│                       ├── util/VisualizeUtils.java    // 可视化工具
│                       └── DemoApplication.java        // 测试入口

3.2 配置类(1分钟)


// YOLOConfig.java
package com.yolo.demo.config;

import lombok.Getter;

import java.util.HashMap;
import java.util.Map;

/**
 * YOLOv26配置(新手无需修改)
 */
@Getter
public class YOLOConfig {
    // 模型路径
    public static final String MODEL_PATH = "models/yolov26n.onnx";
    // 输入尺寸(与导出模型时的imgsz一致)
    public static final int INPUT_WIDTH = 640;
    public static final int INPUT_HEIGHT = 640;
    // 置信度阈值(过滤低置信度目标)
    public static final float CONF_THRESHOLD = 0.35f;
    // NMS IOU阈值(去重重复框)
    public static final float NMS_THRESHOLD = 0.45f;
    // YOLOv26默认类别(80类,新手无需修改)
    public static final Map<Integer, String> CLASS_MAP = new HashMap<>();
    static {
        CLASS_MAP.put(0, "person");
        CLASS_MAP.put(1, "bicycle");
        CLASS_MAP.put(2, "car");
        CLASS_MAP.put(3, "motorcycle");
        CLASS_MAP.put(4, "airplane");
        CLASS_MAP.put(5, "bus");
        CLASS_MAP.put(6, "train");
        CLASS_MAP.put(7, "truck");
        CLASS_MAP.put(8, "boat");
        CLASS_MAP.put(9, "traffic light");
        // 其余类别省略,完整80类可直接复制:
    }
}

3.3 预处理工具类(2分钟)


// PreprocessUtils.java
package com.yolo.demo.util;

import com.yolo.demo.config.YOLOConfig;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Size;

import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgproc.*;

/**
 * 图像预处理:与YOLOv26要求一致
 */
public class PreprocessUtils {

    /**
     * 预处理:BGR→RGB + 缩放 + 归一化 + HWC→CHW
     */
    public static float[] preprocess(Mat srcImg) {
        // 1. BGR转RGB(OpenCV默认BGR)
        Mat rgbImg = new Mat();
        cvtColor(srcImg, rgbImg, COLOR_BGR2RGB);

        // 2. 等比例缩放(640×640)
        Mat resizedImg = new Mat();
        resize(rgbImg, resizedImg, new Size(YOLOConfig.INPUT_WIDTH, YOLOConfig.INPUT_HEIGHT), 0, 0, INTER_LINEAR);

        // 3. 归一化(/255)
        Mat floatImg = new Mat();
        resizedImg.convertTo(floatImg, CV_32F, 1.0 / 255.0);

        // 4. HWC→CHW格式转换
        float[] hwcData = new float[YOLOConfig.INPUT_HEIGHT * YOLOConfig.INPUT_WIDTH * 3];
        floatImg.get(0, 0, hwcData);
        float[] chwData = new float[3 * YOLOConfig.INPUT_HEIGHT * YOLOConfig.INPUT_WIDTH];
        for (int c = 0; c < 3; c++) {
            for (int h = 0; h < YOLOConfig.INPUT_HEIGHT; h++) {
                for (int w = 0; w < YOLOConfig.INPUT_WIDTH; w++) {
                    int hwcIdx = h * YOLOConfig.INPUT_WIDTH * 3 + w * 3 + c;
                    int chwIdx = c * YOLOConfig.INPUT_HEIGHT * YOLOConfig.INPUT_WIDTH + h * YOLOConfig.INPUT_WIDTH + w;
                    chwData[chwIdx] = hwcData[hwcIdx];
                }
            }
        }

        // 释放资源
        rgbImg.release();
        resizedImg.release();
        floatImg.release();
        return chwData;
    }

    /**
     * 还原目标框到原始图像尺寸
     */
    public static int[] restoreBox(float[] box, int srcW, int srcH) {
        float x = box[0], y = box[1], w = box[2], h = box[3];
        float scaleX = (float) srcW / YOLOConfig.INPUT_WIDTH;
        float scaleY = (float) srcH / YOLOConfig.INPUT_HEIGHT;
        // 还原坐标(避免超出图像范围)
        int x1 = (int) Math.max(0, (x - w / 2) * scaleX);
        int y1 = (int) Math.max(0, (y - h / 2) * scaleY);
        int x2 = (int) Math.min(srcW, (x + w / 2) * scaleX);
        int y2 = (int) Math.min(srcH, (y + h / 2) * scaleY);
        return new int[]{x1, y1, x2, y2};
    }
}

3.4 推理引擎类(5分钟)


// YOLOv26Engine.java
package com.yolo.demo.engine;

import ai.onnxruntime.*;
import com.yolo.demo.config.YOLOConfig;
import com.yolo.demo.util.PreprocessUtils;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.opencv.opencv_core.Mat;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * YOLOv26推理核心类
 */
@Slf4j
public class YOLOv26Engine {
    private static YOLOv26Engine instance; // 单例模式(新手简化调用)
    private final ReentrantLock lock = new ReentrantLock();
    private OrtEnvironment env;
    private OrtSession session;

    // 单例初始化
    public static YOLOv26Engine getInstance() {
        if (instance == null) {
            synchronized (YOLOv26Engine.class) {
                if (instance == null) {
                    instance = new YOLOv26Engine();
                    instance.initEngine();
                }
            }
        }
        return instance;
    }

    /**
     * 初始化模型
     */
    private void initEngine() {
        lock.lock();
        try {
            env = OrtEnvironment.getEnvironment();
            OrtSession.SessionOptions options = new OrtSession.SessionOptions();
            options.setIntraOpNumThreads(2); // 线程数(新手无需修改)
            options.setOptimizationLevel(OrtSession.SessionOptions.OptLevel.ALL);
            session = env.createSession(YOLOConfig.MODEL_PATH, options);
            log.info("YOLOv26模型加载成功!");
        } catch (OrtException e) {
            log.error("模型加载失败", e);
            throw new RuntimeException("模型初始化失败");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 核心检测方法
     */
    public List<Map<String, Object>> detect(Mat srcImg) {
        lock.lock();
        List<Map<String, Object>> resultList = new ArrayList<>();
        try {
            int srcW = srcImg.cols();
            int srcH = srcImg.rows();

            // 1. 预处理
            float[] inputData = PreprocessUtils.preprocess(srcImg);
            long[] inputShape = new long[]{1, 3, YOLOConfig.INPUT_HEIGHT, YOLOConfig.INPUT_WIDTH};
            OrtSession.InputTensor inputTensor = OrtSession.InputTensor.createTensor(env, inputData, inputShape);
            Map<String, OrtSession.InputTensor> inputs = new HashMap<>();
            inputs.put("images", inputTensor);

            // 2. 推理
            OrtSession.Result ortResult = session.run(inputs);
            float[][] output = (float[][]) ortResult.get(0).getValue();

            // 3. 解析结果
            resultList = parseOutput(output, srcW, srcH);

            // 释放资源
            inputTensor.close();
            ortResult.close();
        } catch (Exception e) {
            log.error("检测失败", e);
        } finally {
            lock.unlock();
        }
        return resultList;
    }

    /**
     * 解析YOLOv26输出结果
     */
    private List<Map<String, Object>> parseOutput(float[][] output, int srcW, int srcH) {
        List<Map<String, Object>> detectList = new ArrayList<>();
        // YOLOv26输出格式:[8400, 84] → 前4列坐标,后80列类别置信度
        for (int i = 0; i < 8400; i++) {
            float[] boxData = output[i];
            // 筛选置信度最高的类别
            float maxConf = 0.0f;
            int maxClsId = -1;
            for (int j = 4; j < 84; j++) {
                if (boxData[j] > maxConf) {
                    maxConf = boxData[j];
                    maxClsId = j - 4;
                }
            }
            // 过滤低置信度目标
            if (maxConf < YOLOConfig.CONF_THRESHOLD || maxClsId == -1) {
                continue;
            }
            // 还原目标框
            int[] rect = PreprocessUtils.restoreBox(boxData, srcW, srcH);
            // 封装结果
            Map<String, Object> obj = new HashMap<>();
            obj.put("x1", rect[0]);
            obj.put("y1", rect[1]);
            obj.put("x2", rect[2]);
            obj.put("y2", rect[3]);
            obj.put("confidence", maxConf);
            obj.put("classId", maxClsId);
            obj.put("className", YOLOConfig.CLASS_MAP.getOrDefault(maxClsId, "unknown"));
            detectList.add(obj);
        }
        // NMS去重
        return nms(detectList, YOLOConfig.NMS_THRESHOLD);
    }

    /**
     * NMS非极大值抑制(去重重复框)
     */
    private List<Map<String, Object>> nms(List<Map<String, Object>> boxes, float iouThreshold) {
        boxes.sort((a, b) -> Float.compare((float) b.get("confidence"), (float) a.get("confidence")));
        List<Map<String, Object>> result = new ArrayList<>();
        while (!boxes.isEmpty()) {
            Map<String, Object> maxBox = boxes.remove(0);
            result.add(maxBox);
            boxes.removeIf(box -> calculateIOU(maxBox, box) > iouThreshold);
        }
        return result;
    }

    /**
     * 计算IOU(交并比)
     */
    private float calculateIOU(Map<String, Object> a, Map<String, Object> b) {
        int x1 = (int) a.get("x1"), y1 = (int) a.get("y1"), x2 = (int) a.get("x2"), y2 = (int) a.get("y2");
        int bx1 = (int) b.get("x1"), by1 = (int) b.get("y1"), bx2 = (int) b.get("x2"), by2 = (int) b.get("y2");

        int interX1 = Math.max(x1, bx1);
        int interY1 = Math.max(y1, by1);
        int interX2 = Math.min(x2, bx2);
        int interY2 = Math.min(y2, by2);
        int interArea = Math.max(0, interX2 - interX1) * Math.max(0, interY2 - interY1);

        int aArea = (x2 - x1) * (y2 - y1);
        int bArea = (bx2 - bx1) * (by2 - by1);
        return (float) interArea / (aArea + bArea - interArea);
    }

    /**
     * 释放资源
     */
    public void release() {
        lock.lock();
        try {
            if (session != null) session.close();
            if (env != null) env.close();
        } catch (OrtException e) {
            log.error("释放资源失败", e);
        } finally {
            lock.unlock();
        }
    }
}

3.5 可视化工具类(2分钟)


// VisualizeUtils.java
package com.yolo.demo.util;

import org.bytedeco.opencv.opencv_core.*;

import java.util.List;
import java.util.Map;

import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgproc.*;

/**
 * 结果可视化:绘制检测框、类别、置信度
 */
public class VisualizeUtils {

    /**
     * 绘制检测结果
     */
    public static Mat drawResult(Mat srcImg, List<Map<String, Object>> detectList) {
        // 复制原图(避免修改原图)
        Mat drawImg = srcImg.clone();
        // 颜色:红色(检测框)、白色(文字)
        Scalar boxColor = new Scalar(0, 0, 255, 255);
        Scalar textColor = new Scalar(255, 255, 255, 255);

        for (Map<String, Object> obj : detectList) {
            int x1 = (int) obj.get("x1");
            int y1 = (int) obj.get("y1");
            int x2 = (int) obj.get("x2");
            int y2 = (int) obj.get("y2");
            String className = (String) obj.get("className");
            float confidence = (float) obj.get("confidence");

            // 1. 绘制矩形框
            rectangle(drawImg, new Point(x1, y1), new Point(x2, y2), boxColor, 2, LINE_AA, 0);

            // 2. 绘制文字背景(半透明)
            String text = String.format("%s (%.2f)", className, confidence);
            int textSize = 1;
            int textThickness = 1;
            Size textSizeObj = getTextSize(text, FONT_HERSHEY_SIMPLEX, textSize, textThickness, null);
            Rect textRect = new Rect(x1, y1 - 30, textSizeObj.width(), textSizeObj.height() + 10);
            rectangle(drawImg, textRect, boxColor, FILLED, LINE_AA, 0);

            // 3. 绘制文字
            putText(drawImg, text, new Point(x1, y1 - 10), FONT_HERSHEY_SIMPLEX, textSize, textColor, textThickness, LINE_AA, false);
        }
        return drawImg;
    }
}

步骤4:结果可视化(5分钟)

4.1 测试入口类


// DemoApplication.java
package com.yolo.demo;

import com.yolo.demo.engine.YOLOv26Engine;
import com.yolo.demo.util.VisualizeUtils;
import org.bytedeco.opencv.opencv_core.Mat;

import static org.bytedeco.opencv.global.opencv_imgcodecs.*;

import java.util.List;
import java.util.Map;

/**
 * 测试入口:30分钟上手核心
 */
public class DemoApplication {
    public static void main(String[] args) {
        // 1. 准备测试图片(新手可将test.jpg放在项目根目录)
        String imgPath = "test.jpg"; // 替换为自己的图片路径(如包含人物/车辆的图片)
        Mat srcImg = imread(imgPath);
        if (srcImg.empty()) {
            System.out.println("图片加载失败,请检查路径!");
            return;
        }

        // 2. 初始化YOLOv26引擎
        YOLOv26Engine engine = YOLOv26Engine.getInstance();

        // 3. 执行检测
        long start = System.currentTimeMillis();
        List<Map<String, Object>> detectList = engine.detect(srcImg);
        long cost = System.currentTimeMillis() - start;

        // 4. 打印检测结果
        System.out.println("===== 检测结果 =====");
        System.out.printf("耗时:%dms,检测到目标数:%d%n", cost, detectList.size());
        for (Map<String, Object> obj : detectList) {
            System.out.printf("类别:%s,置信度:%.2f,坐标:(%d,%d)-(%d,%d)%n",
                    obj.get("className"), obj.get("confidence"),
                    obj.get("x1"), obj.get("y1"), obj.get("x2"), obj.get("y2"));
        }

        // 5. 可视化并保存结果
        Mat resultImg = VisualizeUtils.drawResult(srcImg, detectList);
        imwrite("result.jpg", resultImg);
        System.out.println("可视化结果已保存为:result.jpg");

        // 6. 释放资源
        engine.release();
        srcImg.release();
        resultImg.release();
    }
}

4.2 运行测试(5分钟)

  1. 在项目根目录放入一张测试图片(命名为test.jpg,建议包含人物、车辆等常见目标);

  2. 运行DemoApplication.main()

  3. 控制台输出检测结果,项目根目录生成result.jpg(带红色检测框的可视化图片)。

常见问题速解(新手必看)

问题现象解决方案
模型加载失败:找不到onnxruntime_jni.dll1. 确认pom.xml的classifier与系统匹配(Windows x64/Linux x86_64);2. 重启IDEA,重新下载依赖
图片加载失败检查test.jpg路径是否正确,确保图片存在且格式为jpg
检测结果为空1. 降低YOLOConfig的CONF_THRESHOLD至0.25;2. 确保测试图片有YOLOv26支持的类别(person/car等)
检测框偏移检查PreprocessUtils的restoreBox方法,确保宽高顺序正确(cols=宽,rows=高)

总结

核心要点回顾

  1. 环境关键:ONNX Runtime的classifier需匹配操作系统(Windows/Linux/x86/ARM),依赖下载优先用阿里云镜像;

  2. 模型适配:YOLOv26的ONNX模型需导出为640×640尺寸,opset=12保证兼容性;

  3. 预处理匹配:必须完成BGR→RGB、归一化、HWC→CHW,否则检测结果异常;

  4. 可视化核心:通过JavaCV绘制矩形框和文字,新手可直接复用VisualizeUtils;

  5. 资源释放:Mat、OrtTensor等原生资源必须手动释放,避免内存泄漏。

本文通过30分钟闭环教程,实现了Java+YOLOv26从环境搭建到可视化的全流程,新手只需跟着步骤复制代码、替换路径,就能快速跑通第一个检测案例。后续可基于此基础,适配自定义数据集、优化推理性能,或对接视频流检测场景。

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:alixiixcom@163.com