什么?OpenCV调用cv2.putText()乱码?寻找支持中文的方法之旅_cv2.puttext 不支持中文
文章标题
- 一、OpenCV
-
- 1.关于
- 2.根因
- 二、Java版
-
- 1.java-opencv(不支持中文,需要编译,支持版本为4.9.0)
-
- 1.1 pom依赖
- 1.2 demo代码
- 1.3 OpenCV库文件
-
- 1.3.1 Windows平台下载安装
- 1.3.2 Linux平台编译
- 1.3.3 验证是否更新
- 1.3.4 so有哪些依赖
- 1.4 docker打包上线
- 1.5 测试结果
- 2. javacv(不支持中文,不需要编译,支持版本为4.11.0)
-
- 2.1 pom依赖
- 2.2 demo代码
- 2.3 maven打包
- 2.4 docker打包上线
- 2.5 测试结果
- 3.java-native版(支持中文,不需要编译,不需要pom依赖)
-
- 3.1 demo代码
- 3.2 docker打包上线
- 3.3 测试结果
- 三、python版
-
- 1. opencv-python不支持中文(我想大多数人都遇到过)
- 2. opencv-python-rolling支持中文(我想大多数人都没想到过)
- 3. demo代码
- 参考
一、OpenCV
Open Source Computer Vision Library
开源的计算机视觉库
https://opencv.org/
https://github.com/opencv/opencv
1.关于
OpenCV(开源计算机视觉库)是一个开源计算机视觉和机器学习软件库。由C++编写,其他语言可以通过动态链接库调用
它拥有 C++、Python、Java 和 MATLAB 接口,并支持 Windows、Linux、 Android 和 Mac OS。
2.根因
cv2.putText 基于 OpenCV 的底层绘制函数,这些函数通常只支持单字节的 ASCII 字符集,无法识别和处理像中文这样的多字节字符。
二、Java版
需求描述:在一张图片里面画框,并在框上面添加标签和置信度。具体数据结构如下:
public class Detection { private String label; private float[] bbox; // 边界框坐标 [x1, y1, x2, y2](归一化) private float confidence; // 置信度 public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public float[] getBbox() { return bbox; } public void setBbox(float[] bbox) { this.bbox = bbox; } public float getConfidence() { return confidence; } public void setConfidence(float confidence) { this.confidence = confidence; }}
测试图片如下:
测试数据如下:
[ { \"label\": \"卫衣\", \"bbox\": [ 0.18, 0.25, 0.60, 0.90 ], \"confidence\": 0.95, \"description\": \"左侧人物穿着黑色卫衣,上半身从肩膀到腰部清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。\" }, { \"label\": \"卫衣\", \"bbox\": [ 0.52, 0.20, 0.87, 0.74 ], \"confidence\": 0.95, \"description\": \"右侧人物同样穿着黑色卫衣,上半身从肩膀到腰部也清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。处理多人场景时,按照从左到右的顺序进行标注。\" }]
1.java-opencv(不支持中文,需要编译,支持版本为4.9.0)
起初参见了这篇文章:Intro to OpenCV with Java
1.1 pom依赖
<dependency> <groupId>org.openpnp</groupId> <artifactId>opencv</artifactId> <version>4.9.0-0</version></dependency>
1.2 demo代码
// 静态代码块加载OpenCV库 static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public String bbox(byte[] fileBytes, List<Detection> detections) { // 1. 读取图像文件 Mat img = Imgcodecs.imdecode(new MatOfByte(fileBytes), Imgcodecs.IMREAD_COLOR); if (img.empty()) { throw new IllegalArgumentException(\"无法读取图像\"); } // 2. 获取图像尺寸 int h = img.rows(); int w = img.cols(); // 3. 绘制边界框和置信度 for (Detection detection : detections) { float[] bbox = detection.getBbox(); float confidence = detection.getConfidence(); // 转换归一化坐标到绝对坐标 int x1 = (int) (bbox[0] * w); int y1 = (int) (bbox[1] * h); int x2 = (int) (bbox[2] * w); int y2 = (int) (bbox[3] * h); // 绘制红色矩形框(OpenCV中颜色通道为BGR,红色为(0,0,255)) Imgproc.rectangle( img, new Point(x1, y1), new Point(x2, y2), new Scalar(0, 0, 255), // BGR颜色 3 // 线宽 ); // 添加置信度标签 String label = detection.getLabel() + String.format(\" %.2f\", confidence); Imgproc.putText( img, label, new Point(x1, y1 - 10), // 文本位置 Imgproc.FONT_HERSHEY_SIMPLEX, // 字体 0.7, // 字体大小 new Scalar(0, 0, 255), // 文本颜色(红色) 2 // 文本线宽 ); } // 4. 将Mat转换为Base64 MatOfByte matOfByte = new MatOfByte(); Imgcodecs.imencode(\".jpg\", img, matOfByte); byte[] byteArray = matOfByte.toArray(); // 5. 编码为Base64字符串 return Base64.getEncoder().encodeToString(byteArray); }
1.3 OpenCV库文件
1.3.1 Windows平台下载安装
https://opencv-java-tutorials.readthedocs.io/en/latest/01-installing-opencv-for-java.html#install-opencv-3-x-under-windows
下载opencv:https://github.com/opencv/opencv/releases/download/4.9.0/opencv-4.9.0-windows.exe
将opencv_java490.dll
放到:C:\\Windows\\System32中
或可以制定路径:-Djava.library.path=/nfs/opencv
1.3.2 Linux平台编译
docker build -t dockerdance/java-opencv:17.0.16_8-jdk-noble-4.9.0 . -f Dockerfile-opencv
# https://whichjdk.com/# https://adoptium.net/zh-CN/temurin/releases?version=8&os=any&arch=any Temurin 8.0.462+8# https://adoptium.net/zh-CN/temurin/releases?version=17&os=any&arch=any Temurin 17.0.16+8# https://releases.ubuntu.com/ noble Ubuntu 24.04.2 LTS# https://hub.docker.com/layers/library/eclipse-temurin/8u462-b08-jdk-noble/images/sha256-8a5c518422bbf3017338bd7ee3da6ae8a7f7643f266f2367d41a737f6fa4c51a# https://hub.docker.com/layers/library/eclipse-temurin/17.0.16_8-jdk-noble/images/sha256-bdc4fab96f2ebc23fb7014023e22d522f1e765253876cc60ec896156a10cf01cFROM eclipse-temurin:17.0.16_8-jdk-nobleLABEL authors=\"d\"# 创建工作目录WORKDIR /usr/src/opencv_build# 下载 OpenCV 4.9.0 源码COPY opencv-4.9.0.tar.gz .#RUN wget https://github.com/opencv/opencv/archive/4.9.0.tar.gz -O opencv-4.9.0.tar.gz# 解压RUN tar -zxvf opencv-4.9.0.tar.gz# 更新包索引RUN apt update# 安装编译工具RUN apt install -y build-essential cmake git# 安装 OpenCV 依赖的图像/视频处理库RUN apt install -y libjpeg-dev libpng-dev libtiff-dev libwebp-dev \\ libavcodec-dev libavformat-dev libswscale-dev \\ libv4l-dev libxvidcore-dev libx264-dev \\ libgtk-3-dev libatlas-base-dev gfortranRUN apt install -y libfreetype6 libfreetype6-dev libharfbuzz0b libharfbuzz-dev# 创建编译目录WORKDIR /usr/src/opencv_build/opencv-4.9.0/build# 配置 CMake(关键:启用 Java 绑定)RUN cmake -DCMAKE_BUILD_TYPE=RELEASE \\ -DCMAKE_INSTALL_PREFIX=/usr/local \\ -DBUILD_SHARED_LIBS=OFF \\ -DBUILD_opencv_java=ON \\ -DOPENCV_GENERATE_PKGCONFIG=ON \\ -DWITH_FREETYPE=ON \\ -DWITH_JPEG=ON \\ -DWITH_PNG=ON \\ ..# 编译(根据 CPU 核心数调整 -j 参数,如 4 核用 -j4)RUN make -j$(nproc)# 安装到系统RUN make install# 更新动态链接库缓存RUN ldconfigWORKDIR /appENTRYPOINT [\"top\", \"-b\"]
运行docker并将里面编译好的so复制出来:
docker run -d dockerdance/java-opencv:17.0.16_8-jdk-noble-4.9.0docker cp ea254c5cb3c5:/usr/src/opencv_build/opencv-4.9.0/build/lib/* /usr/local/lib
libopencv_java490.so
放到:/usr/local/lib中
也可以制定路径:-Djava.library.path=/nfs/opencv
1.3.3 验证是否更新
ldconfig -p | grep libopencv_ml.so.409
1.3.4 so有哪些依赖
readelf -d libopencv_java490.so|grep NEED
1.4 docker打包上线
docker build -t dockerdance/annotation_opencv:1.0.0 .
# https://whichjdk.com/# https://adoptium.net/zh-CN/temurin/releases?version=8&os=any&arch=any Temurin 8.0.462+8# https://adoptium.net/zh-CN/temurin/releases?version=17&os=any&arch=any Temurin 17.0.16+8# https://releases.ubuntu.com/ noble Ubuntu 24.04.2 LTS# https://hub.docker.com/layers/library/eclipse-temurin/8u462-b08-jdk-noble/images/sha256-8a5c518422bbf3017338bd7ee3da6ae8a7f7643f266f2367d41a737f6fa4c51a# https://hub.docker.com/layers/library/eclipse-temurin/17.0.16_8-jdk-noble/images/sha256-bdc4fab96f2ebc23fb7014023e22d522f1e765253876cc60ec896156a10cf01cFROM eclipse-temurin:17.0.16_8-jdk-nobleLABEL authors=\"d\"# 更新包索引RUN apt update# 安装 OpenCV 依赖的图像/视频处理库RUN apt install -y ffmpegWORKDIR /usr/local/libCOPY src/main/resources/lib/libopencv_*.so /usr/local/libWORKDIR /appCOPY target/*.jar app.jarENTRYPOINT [\"/bin/sh\", \"-c\", \"ldconfig && ldconfig -p | grep libopencv_ml.so.409 && java -Djava.library.path=/usr/local/lib -jar app.jar\"]
docker run -d -p 8080:8080 dockerdance/annotation_opencv:1.0.0
1.5 测试结果
curl -O \"https://i-blog.csdnimg.cn/direct/ceda80935d124108ad3394641ebe5aa4.jpeg\"curl --location --request POST \'http://localhost:8080/draw-bboxes\' \\--header \'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\' \\--header \'Content-Type: multipart/form-data\' \\--form \'file=@\"ceda80935d124108ad3394641ebe5aa4.jpeg\"\' \\--form \'detections=\"[ { \\\"label\\\": \\\"卫衣\\\", \\\"bbox\\\": [0.18, 0.25, 0.60, 0.90], \\\"confidence\\\": 0.95, \\\"description\\\": \\\"左侧人物穿着黑色卫衣,上半身从肩膀到腰部清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。\\\" }, { \\\"label\\\": \\\"卫衣\\\", \\\"bbox\\\": [0.52, 0.20, 0.87, 0.74], \\\"confidence\\\": 0.95, \\\"description\\\": \\\"右侧人物同样穿着黑色卫衣,上半身从肩膀到腰部也清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。处理多人场景时,按照从左到右的顺序进行标注。\\\" } ]\"\'
将生成的base64转为图片:https://base64.guru/converter/decode/image


2. javacv(不支持中文,不需要编译,支持版本为4.11.0)
2.1 pom依赖
<dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.12</version></dependency>
2.2 demo代码
public String bbox(byte[] fileBytes, List<Detection> detections) throws Exception { try { // 将字节数据转换为Mat对象 Mat img = opencv_imgcodecs.imdecode(new Mat(fileBytes), opencv_imgcodecs.IMREAD_COLOR); if (img.empty()) { throw new Exception(\"无法读取图像\"); } // 获取图像尺寸 int h = img.rows(); int w = img.cols(); // 遍历所有检测结果并绘制边界框 for (Detection detection : detections) { float[] bbox = detection.getBbox(); float confidence = detection.getConfidence(); // 转换归一化坐标到绝对坐标 int x1 = (int) (bbox[0] * w); int y1 = (int) (bbox[1] * h); int x2 = (int) (bbox[2] * w); int y2 = (int) (bbox[3] * h); // 绘制红色矩形框 (OpenCV中颜色是BGR格式) opencv_imgproc.rectangle(img, new Point(x1, y1), new Point(x2, y2), new Scalar(0, 0, 255, 0), 3, opencv_imgproc.LINE_AA, 0); // 准备置信度标签 String label = detection.getLabel() + String.format(\" %.2f\", confidence); // 绘制标签 opencv_imgproc.putText(img, label, new Point(x1, y1 - 10), opencv_imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(0, 0, 255, 0), 2, opencv_imgproc.LINE_AA, false); } // 将Mat编码为JPEG ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try (Java2DFrameConverter converter = new Java2DFrameConverter(); FrameConverter<Mat> frameConverter = new OpenCVFrameConverter.ToMat()) { Frame frame = frameConverter.convert(img); BufferedImage bufferedImage = converter.convert(frame); javax.imageio.ImageIO.write(bufferedImage, \"jpg\", outputStream); } // 转换为Base64字符串 return Base64.getEncoder().encodeToString(outputStream.toByteArray()); } catch (Exception e) { throw new Exception(\"无法读取图像\"); } }
2.3 maven打包
原生二进制文件本身就很大,我们需要为每个支持的平台使用不同的库。但是,如果您的应用程序不依赖所有这些库,或者不需要支持所有这些平台,那么除了手动逐个排除依赖项或从超级 JAR 中删除文件之外,还有一些方法可以轻松减少依赖项的数量。
https://github.com/bytedeco/javacpp-presets/wiki/Reducing-the-Number-of-Dependencies
指定平台可以减少jar的大小
mvn clean package -Dmaven.test.skip=true -Djavacpp.platform=linux-x86_64
2.4 docker打包上线
docker build -t dockerdance/annotation_javacv:1.0.0 .
# https://whichjdk.com/# https://adoptium.net/zh-CN/temurin/releases?version=8&os=any&arch=any Temurin 8.0.462+8# https://adoptium.net/zh-CN/temurin/releases?version=17&os=any&arch=any Temurin 17.0.16+8# https://releases.ubuntu.com/ noble Ubuntu 24.04.2 LTS# https://hub.docker.com/layers/library/eclipse-temurin/8u462-b08-jdk-noble/images/sha256-8a5c518422bbf3017338bd7ee3da6ae8a7f7643f266f2367d41a737f6fa4c51a# https://hub.docker.com/layers/library/eclipse-temurin/17.0.16_8-jdk-noble/images/sha256-bdc4fab96f2ebc23fb7014023e22d522f1e765253876cc60ec896156a10cf01cFROM eclipse-temurin:17.0.16_8-jdk-nobleLABEL authors=\"duhongming\"WORKDIR /appCOPY target/*.jar app.jarENTRYPOINT [\"java\", \"-jar\",\"app.jar\"]
docker run -d -p 8080:8080 dockerdance/annotation_javacv:1.0.0
2.5 测试结果
curl -O \"https://i-blog.csdnimg.cn/direct/ceda80935d124108ad3394641ebe5aa4.jpeg\"curl --location --request POST \'http://localhost:8080/draw-bboxes\' \\--header \'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\' \\--header \'Content-Type: multipart/form-data\' \\--form \'file=@\"ceda80935d124108ad3394641ebe5aa4.jpeg\"\' \\--form \'detections=\"[ { \\\"label\\\": \\\"卫衣\\\", \\\"bbox\\\": [0.18, 0.25, 0.60, 0.90], \\\"confidence\\\": 0.95, \\\"description\\\": \\\"左侧人物穿着黑色卫衣,上半身从肩膀到腰部清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。\\\" }, { \\\"label\\\": \\\"卫衣\\\", \\\"bbox\\\": [0.52, 0.20, 0.87, 0.74], \\\"confidence\\\": 0.95, \\\"description\\\": \\\"右侧人物同样穿着黑色卫衣,上半身从肩膀到腰部也清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。处理多人场景时,按照从左到右的顺序进行标注。\\\" } ]\"\'
将生成的base64转为图片:https://base64.guru/converter/decode/image


3.java-native版(支持中文,不需要编译,不需要pom依赖)
3.1 demo代码
// 中文字体 private static Font chineseFont; static { // 初始化支持中文的字体 try { // 尝试加载系统中的中文字体,可根据实际情况修改字体名称// chineseFont = new Font(\"SimHei\", Font.PLAIN, 14); // 如果需要使用自定义字体文件,可使用以下代码 chineseFont = Font.createFont(Font.TRUETYPE_FONT, AnnotationNativeApplication.class.getResourceAsStream(\"/fonts/simhei.ttf\")) .deriveFont(14f); } catch (Exception e) { // 字体加载失败时使用默认字体 chineseFont = new Font(Font.SANS_SERIF, Font.PLAIN, 14); System.err.println(\"警告:中文字体加载失败,使用默认字体,可能导致中文显示异常\"); } } public String bbox(InputStream file, List<Detection> detections) throws IOException { // 1. 读取图像文件 // 使用ImageIO读取流并转换为BufferedImage BufferedImage bufferedImage = ImageIO.read(file); // 2. 获取图像尺寸 int h = bufferedImage.getHeight(); int w = bufferedImage.getWidth(); // 创建绘图对象 Graphics2D g2d = bufferedImage.createGraphics(); // 设置抗锯齿,使文字更清晰 g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // 3. 绘制边界框和置信度 for (Detection detection : detections) { float[] bbox = detection.getBbox(); float confidence = detection.getConfidence(); // 转换归一化坐标到绝对坐标 int x1 = (int) (bbox[0] * w); int y1 = (int) (bbox[1] * h); int x2 = (int) (bbox[2] * w); int y2 = (int) (bbox[3] * h); // 准备置信度标签 String label = detection.getLabel() + String.format(\" %.2f\", confidence); // 绘制红色矩形框 (注意: BufferedImage使用RGB格式) g2d.setColor(Color.RED); g2d.setStroke(new BasicStroke(3)); g2d.drawRect(x1, y1, x2 - x1, y2 - y1); // 设置字体 g2d.setFont(chineseFont); // 计算标签位置,确保不超出图像顶部 int labelY = y1 - 10; if (labelY < 15) { // 字体高度大约15px labelY = 15; } // 绘制标签 g2d.drawString(label, x1, labelY); } // 释放资源 g2d.dispose(); // 将Mat编码为JPEG ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ImageIO.write(bufferedImage, \"jpg\", outputStream); // 转换为Base64字符串 return Base64.getEncoder().encodeToString(outputStream.toByteArray()); }
3.2 docker打包上线
docker build -t dockerdance/annotation_native:1.0.0 .
# https://whichjdk.com/# https://adoptium.net/zh-CN/temurin/releases?version=8&os=any&arch=any Temurin 8.0.462+8# https://adoptium.net/zh-CN/temurin/releases?version=17&os=any&arch=any Temurin 17.0.16+8# https://releases.ubuntu.com/ noble Ubuntu 24.04.2 LTS# https://hub.docker.com/layers/library/eclipse-temurin/8u462-b08-jdk-noble/images/sha256-8a5c518422bbf3017338bd7ee3da6ae8a7f7643f266f2367d41a737f6fa4c51a# https://hub.docker.com/layers/library/eclipse-temurin/17.0.16_8-jdk-noble/images/sha256-bdc4fab96f2ebc23fb7014023e22d522f1e765253876cc60ec896156a10cf01cFROM eclipse-temurin:17.0.16_8-jdk-nobleLABEL authors=\"duhongming\"WORKDIR /appCOPY target/*.jar app.jarENTRYPOINT [\"java\", \"-jar\",\"app.jar\"]
docker run -d -p 8080:8080 dockerdance/annotation_native:1.0.0
3.3 测试结果
curl -O \"https://i-blog.csdnimg.cn/direct/ceda80935d124108ad3394641ebe5aa4.jpeg\"curl --location --request POST \'http://localhost:8080/draw-bboxes\' \\--header \'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\' \\--header \'Content-Type: multipart/form-data\' \\--form \'file=@\"ceda80935d124108ad3394641ebe5aa4.jpeg\"\' \\--form \'detections=\"[ { \\\"label\\\": \\\"卫衣\\\", \\\"bbox\\\": [0.18, 0.25, 0.60, 0.90], \\\"confidence\\\": 0.95, \\\"description\\\": \\\"左侧人物穿着黑色卫衣,上半身从肩膀到腰部清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。\\\" }, { \\\"label\\\": \\\"卫衣\\\", \\\"bbox\\\": [0.52, 0.20, 0.87, 0.74], \\\"confidence\\\": 0.95, \\\"description\\\": \\\"右侧人物同样穿着黑色卫衣,上半身从肩膀到腰部也清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。处理多人场景时,按照从左到右的顺序进行标注。\\\" } ]\"\'
将生成的base64转为图片:https://base64.guru/converter/decode/image


三、python版
看了很多网上的资料,以及询问了很多AI的意见,我发现都不能满足我的要求。解决方法都是:
一、转换为Pillow
二、使用FreeType
三、使用Pygame
上面的三种方法都能解决中文乱码的问题,我也成功显示了中文结果。但是我的项目涉及视频处理,对于实时性要求比较高,以上的三种方法对我而言都不理想,因为都大幅增加了处理的时间,比如当我使用Pillow绘制文本时,总时长为60秒的视频,只做处理不绘制任何文本的情况下用时18-20秒,但绘制文本后居然用了30-33秒。也就是说绘制文本居然增加了50%的用时,这对于实时性要求高的场景明显不合理。上面的三种解决方法都会大幅增加用时,具体的用时为Pillow>Pygame>FreeType。经过我实验下来,我发现OpenCV读取视频并保存视频不做任何处理的情况下用时5-6秒,使用cv2.putText()绘制文本用时只增加2-4秒。所以我决定找到使用cv2.putText()绘制中文文本的方法。
1. opencv-python不支持中文(我想大多数人都遇到过)
requirements.txt
opencv-python
2. opencv-python-rolling支持中文(我想大多数人都没想到过)
requirements.txt
opencv-python-rollingnumpy<2
3. demo代码
import base64import cv2def draw_bboxes(filename, detections): # 1. 读取图像文件(从字节数据) # 将字节数据转换为numpy数组 # nparr = np.frombuffer(file_bytes, np.uint8) # 解码为OpenCV图像(BGR格式) img = cv2.imread(filename, cv2.IMREAD_COLOR) if img is None: raise ValueError(\"无法读取图像\") # 2. 获取图像尺寸 h, w = img.shape[:2] # 高度和宽度(rows, cols) # 3. 绘制边界框和置信度 for detection in detections: bbox = detection[\"bbox\"] confidence = detection[\"confidence\"] # 转换归一化坐标到绝对坐标 x1 = int(bbox[0] * w) y1 = int(bbox[1] * h) x2 = int(bbox[2] * w) y2 = int(bbox[3] * h) # 绘制红色矩形框(OpenCV中颜色通道为BGR,红色为(0,0,255)) cv2.rectangle( img, (x1, y1), # 左上角点 (x2, y2), # 右下角点 (0, 0, 255), # BGR颜色(红色) 3 # 线宽 ) # 添加置信度标签 label = f\"{detection[\'label\']} {confidence:.2f}\" cv2.putText( img, label, (x1, y1 - 10), # 文本位置 cv2.FONT_HERSHEY_SIMPLEX, # 字体 0.7, # 字体大小 (0, 0, 255), # 文本颜色(红色) 2 # 文本线宽 ) cv2.imshow(\"image\", img) # 4. 将图像转换为Base64 # 编码为JPG格式 ret, buffer = cv2.imencode(\'.jpg\', img) if not ret: raise RuntimeError(\"无法编码图像为JPG格式\") # 5. 编码为Base64字符串 byte_array = buffer.tobytes() return base64.b64encode(byte_array).decode(\'utf-8\')base64_str = draw_bboxes(\'test.jpg\', [{\"label\": \"卫衣\", \"bbox\": [0.18, 0.25, 0.60, 0.90], \"confidence\": 0.95, \"description\": \"左侧人物穿着黑色卫衣,上半身从肩膀到腰部清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。\"}, {\"label\": \"卫衣\", \"bbox\": [0.52, 0.20, 0.87, 0.74], \"confidence\": 0.95, \"description\": \"右侧人物同样穿着黑色卫衣,上半身从肩膀到腰部也清晰可见。锚框紧密包围其上半身区域,置信度高因为图像清晰且无遮挡。处理多人场景时,按照从左到右的顺序进行标注。\"}])print(base64_str)


参考
https://www.baeldung.com/java-opencv
https://blog.csdn.net/Luobinhai/article/details/145533477
https://zhuanlan.zhihu.com/p/615815756