当前位置: 首页 > news >正文

计算机视觉:基于YOLOv11 实例分割与OpenCV 在 Java 中的实现图像实例分割

什么是实例分割

实例分割比目标检测更进一步,涉及识别图像中的单个对象并将其从图像其余部分中分割出来。

YOLO模型简介

YOLO(You Only Look Once)是最著名的目标检测系统之一。它具有极高的速度和准确性,是入门目标检测最便捷的途径之一。其文档极其完善,通过大量示例进行了详尽说明。它还拥有庞大的研究人员、开发者和爱好者社区,分享各种改进并为项目做出贡献。

Python中的YOLO使用示例

通过Python开始使用YOLO的集成过程非常顺畅,其快速开始实例分割实验的能力令人印象深刻。推理过程仅需4行代码即可完成:

from ultralytics import YOLO
# 加载YOLOv11模型
model = YOLO("yolo11n-seg.pt")
# 运行预测
results = model.predict('/path/to/image.jpg')
# 显示结果
results[0].show()

运行结果示例:
在这里插入图片描述

在这里插入图片描述

Java中集成YOLOv11的步骤

1. 项目配置

作为一名Java开发者,在简单的Java项目中尝试此功能的过程并不那么直接。特别是理解推理输出的后处理需要花费大量时间。

首先需要创建一个简单的Java Gradle或Maven项目,并添加OpenCV依赖:

Gradle配置(build.gradle)
plugins {// 应用application插件以支持构建Java CLI应用程序id 'application'
}repositories {// 使用Maven Central解析依赖mavenCentral()
}dependencies {implementation 'org.openpnp:opencv:4.9.0-0'...
Maven配置(pom.xml)
<dependency><groupId>org.openpnp</groupId><artifactId>opencv</artifactId><version>4.9.0-0</version>
</dependency>

2. 基础设置

在进入分割部分之前,先进行一些基础设置。使用OpenCV读取和显示图像,以确保配置正确。加载OpenCV库,从资源文件夹读取图像(示例中使用单张图像bike.jpg),并使用OpenCV HighGui显示:

package org.tutorial;
import nu.pattern.OpenCV;
import org.opencv.core.Mat;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;public class InstanceSegmentation {private static final String IMAGE_NAME = "bike.jpg";public static void main(String[] args) {OpenCV.loadLocally();String imagePath = ResourceUtils.getResourcePath(IMAGE_NAME);Mat image = Imgcodecs.imread(imagePath);HighGui.imshow( "图像", image );HighGui.waitKey(0);HighGui.destroyAllWindows();System.exit(0);}
}

3. 辅助工具类

处理文件系统时,准备工具类可以专注于目标检测,而不必考虑从何处加载图像或模型。以下是ResourceUtils.java辅助类:

import java.net.URL;public class ResourceUtils {public static String getResourcePath(String resourceName){URL resourceUrl = App.class.getClassLoader().getResource( resourceName );if(resourceUrl == null){throw new RuntimeException("未找到名为"+resourceName+ "的资源");}String resourcePath = resourceUrl.getPath();if(resourcePath.isEmpty()) {throw new RuntimeException("从资源URL获取路径时出错");}return resourcePath;}
}

4. 模型准备

使用OpenCV的深度神经网络模块,需要将PyTorch或TensorFlow等框架中训练的模型转换为ONNX(开放神经网络交换)格式。

转换YOLO模型为ONNX格式

推荐通过Google Colab使用Python完成转换:

!pip install ultralytics
from ultralytics import YOLO
model = YOLO("yolo11n-seg.pt")
success = model.export(format="onnx")

YOLO模型(包括早期版本)默认在COCO(上下文常见对象)数据集上进行训练,该数据集包含80个类别,包括人、汽车、自行车、狗、猫等等。

完成转换后,下载yolov11n-seg.onnx模型并保存到Java项目的resources文件夹中。

5. 推理前的准备步骤

后续步骤包括:

  1. 为模型准备输入图像
  2. 加载模型
  3. 运行推理
  4. 从结果中提取分割信息
  5. 可视化结果
准备输入图像

为YOLOv11模型准备图像,包括调整大小(该YOLO模型的IMG_SIZE为640像素):

// 此步骤包括将BGR转换为RGB
Mat inputBlob = Dnn.blobFromImage(image, 1.0 / 255.0,new Size(IMG_SIZE, IMG_SIZE),// 这里我们提供卷积神经网络期望的空间尺寸new Scalar(new double[]{0.0, 0.0, 0.0}),true, false);

最后两个布尔标志位说明:

  • swapRB:指示是否需要对3通道图像交换首尾通道的标志位(在OpenCV中,默认图像格式是BGR而非更常见的RGB,因此设为true
  • crop:指示调整大小后是否对图像进行裁剪的标志位
加载模型并设置输入
String modelPath = ResourceUtils.getResourcePath(MODEL_NAME);
Net net = Dnn.readNetFromONNX(modelPath);
net.setInput(inputBlob);
运行推理
List<String> outNames = net.getUnconnectedOutLayersNames();
List<Mat> outputsList = new ArrayList<>();
net.forward(outputsList, outNames);
  • net.getUnconnectedOutLayersNames():返回网络输出层的名称
  • outputsList:在模型前向传播后保存结果(实际输出)
  • net.forward:用于运行网络的前向传播,通过模型各层处理输入数据来计算输出结果

后处理过程

net.forward调用获得输出后,需要进行后处理以提取分割信息。

输出结果分析

扩展代码片段,打印outputsList中的预测结果:

List<String> outNames = net.getUnconnectedOutLayersNames();
List<Mat> outputsList = new ArrayList<>();
net.forward(outputsList, outNames);// 获取相关输出并打印出来
Mat boxOutputs = outputsList.get(0);
Mat maskOutputs = outputsList.get(1);LOGGER.info("框输出: "+boxOutputs.toString());
LOGGER.info("掩码输出: "+maskOutputs.toString());

boxOutputs是边界框预测,形状为**[1, 116, 8400]**,包含8400个潜在检测的预测,每个检测有116个值:

  • 4个值用于边界框坐标(center_x, center_y, width, height)
  • 80个值用于类别概率(COCO数据集的80个类别)
  • 32个值用于掩码系数(与maskOutputs结合生成分割掩码)

矩阵转置处理

为了正确处理8400个预测(每个对应116个值),需要将矩阵转置为8400x116

Mat mat2D = boxOutputs.reshape(1, (int) boxOutputs.size().width); // 第二个参数是行数
Core.transpose(mat2D, mat2D);

提取相关信息

从输出中提取信息的步骤:

  1. 遍历8400行中的每一行
  2. 对于每一行,提取80个类别概率并找到最大值
  3. 根据定义的阈值检查该最大值(例如,仅保留分数 > 0.6的预测)
  4. 提取掩码系数(从总共116个值中取出最后32个值)
  5. 为此检测生成掩码
var segmentationMasks = new ArrayList<Mat>();LOGGER.info("—-开始分析推理结果—-");
for (int i = 0; i < mat2D.rows(); i++)
{Mat detectionMat = mat2D.row(i);List<Double> scores = new ArrayList<>();for (int j = 4; j < NUM_CLASSES+4; j++) {scores.add(mat2D.get(i, j)[0]);}MaxScore maxScore = ScoreUtils.findMaxScore( scores );if(maxScore.maxValue() < 0.6) {continue;}// 提取掩码系数Mat maskCoeffs = detectionMat.colRange(4 + NUM_CLASSES, 4 + NUM_CLASSES + 32);// 为此检测生成掩码Mat objectMask = generateMask(maskOutputs, maskCoeffs);segmentationMasks.add(objectMask);
}

分数计算工具类

ScoreUtils用于从双精度数组中找出最大值:

record MaxScore (double maxValue, int indexOfMax) {}public class ScoreUtils {public static MaxScore findMaxScore(List<Double> array) {double max = array.get(0);int indexOfMax = 0;for (int i = 1; i < array.size(); i++) {if (array.get(i) > max) {max = array.get(i);indexOfMax = i;}}return new MaxScore( max, indexOfMax );}
}

掩码系数提取

提取掩码系数的代码:

Mat maskCoeffs = detectionMat.colRange(4 + NUM_CLASSES, 4 + NUM_CLASSES + 32);

获取从索引4 + NUM_CLASSES(本例中为84)到NUM_CLASSES+32(本例中为116)的值。
在这里插入图片描述

生成掩码

查看for循环的最后两个步骤:

// 为此检测生成掩码
Mat objectMask = generateMask(maskOutputs, maskCoeffs);
segmentationMasks.add(objectMask);

还将研究如何将掩码叠加到原始图像上,详细检查maskOutputs,并在先前步骤中提取的32个掩码系数与maskOutputs中的32个原型掩码之间执行矩阵乘法。

结论

在快速实验目标检测、实例分割以及与大型语言模型(LLMs)集成方面,Java正变得越来越强大。本系列将帮助您了解借助OpenCV在这个生态系统中目前可以实现的功能。

http://www.dtcms.com/a/394870.html

相关文章:

  • 【实战】Spring Boot 3.x整合Redis:注解式缓存与分布式锁最佳实践
  • 密钥耳语-一个轻量、易备份、支持命令行与图形界面的口令派生加密工具 具有 CLI 和 GUI 的轻量级密码衍生加密工具
  • AI重塑流量背后,微软广告打造下一代广告生态
  • 低代码数字化时代的开发新范式
  • 微信小程序“无损去水印精灵”技术解析大纲
  • 少儿舞蹈小程序(18)订单确认
  • Uniapp X 打包抖音小程序教程
  • uni-app中实现在input的placeholder中添加图标
  • vue面试题集锦
  • 基于Springboot+UniApp+Ai实现模拟面试小工具十二:模拟面试功能实现
  • 基于Springboot+UniApp+Ai实现模拟面试小工具十一:主页功能及简历上传功能实现
  • BGP选路“十一步”法则
  • MITRE ATLAS 对抗威胁矩阵与 LLM 安全
  • 第5章:技术深度与广度:构筑你的核心壁垒(1)
  • 洞察未来:Temporal.io 如何赋能复杂模拟引擎的韧性与智能
  • Android 实例 - Android 圆形蒙版(Android 圆形蒙版实现、圆形蒙版解读)
  • PyCharm 在 Linux 上的安装指南
  • Linux 入门:开启开源世界的大门
  • ​​[硬件电路-321]:数字电路的两大家族CMOS(来源于MOS三极管管)与TTL(来源于BJT三极管)
  • 【GitHub每日速递 250922】开源 AI 搜索引擎 Perplexica:本地大模型 + 多模式搜索,免费又强大!
  • CCF-CSP-S 2021 初赛解析
  • 现在如何使用docker下载
  • 【Proteus仿真】AT89C51单片机并行数据转换为串行仿真
  • Docker 容器详解及实操,从新手>入门>拿捏,巨详细
  • 【ASP.NET Core】身份认证——Identity标识框架指南
  • [Nodejs+LangChain+Ollama] 2.提示词实践
  • i.MX6ULL移植内核6.6(二)GPIO子系统和LED子系统
  • VLC Media取消视频文件名前置显示
  • 在unity urp项目中 通过图片创建材质(透明光晕)
  • OneSignal PHP SDK v2 官方资源