完美解决labelimg xml转可视化中文乱码问题,不用matplotlib

背景简述

我们有一批标注项目要转可视化,因为之前没有做过,然后网上随意找了一段代码测试完美(并没有)搞定,开始疯狂标注,当真正要转的时候傻眼了,因为测试的时候用的是英文标签,实际标注的是中文标签,结果都是一大堆??????,

结果瞬间让我满脑袋??????,赶紧找资料解决,各种方法试了个遍,网上大多数都是用cv2+matplotlib实现的计算和渲染,所以解决的主要思想就是集中在各种显示的设置matplotlib字体,然并卵;最后找到一种另辟蹊径的办法使用PIL+cv2实现,最后完美解决,

贴上解决代码:

python 复制代码
import cv2
import os
import numpy as np  
from PIL import Image, ImageDraw, ImageFont
import xml.etree.ElementTree as ET

data_path = 'E:\\test\\tianjingulou'
imgs_path = os.path.join(data_path, "img")
anns_path = os.path.join(data_path, "xml")
result_path = os.path.join(data_path)

img_names = set([os.path.splitext(i)[0] for i in os.listdir(imgs_path)])
ann_names = set([os.path.splitext(i)[0] for i in os.listdir(anns_path)])
img_names = list(img_names)
ann_names = list(ann_names)

for i in range(len(img_names)):
    img_path = os.path.join(imgs_path, img_names[i] + ".jpg")
    img_bgr = cv2.imread(img_path)

    xml_path = os.path.join(anns_path, ann_names[i] + ".xml")

    xml_inf = open(xml_path, encoding='utf-8')
    tree = ET.parse(xml_inf)
    root = tree.getroot()

    bbox_color = (0, 129, 255)
    bbox_thickness = 2
    # 把rgb转成16进制'#0081FF'
    bbox_color_str = "#{:02x}{:02x}{:02x}".format(*bbox_color)

    # 把rgb转成bgr再转16进制'#FF8100'
    # bbox_color_rgb = bbox_color[::-1]
    # bbox_color_str = "#{:02x}{:02x}{:02x}".format(*bbox_color_rgb)

    bbox_labelstr = {
        'font_size': 16,
        'font_thickness': 2,
        'offset_x': 0,
        'offset_y': -20,
    }

    # 创建一个空白图像
    img_pil = Image.fromarray(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img_pil)

    # 设置字体  SimHei.ttf黑体,msyh.ttf微软雅黑
    # 打开命令行窗口或者Anaconda Prompt,输入python,进入python解释器窗口,
    #   输入import matplotlib;引入可视化库;
    #   然后输入print(matplotlib.matplotlib_fname())打印出当前库所在位置;
    #   进入到上面打印出的路径下字体目录:mpl-data\\fonts\\ttf,下载中文字体放进去
    font_path = "D:\\ProgramData\\anaconda3\\Lib\\site-packages\\matplotlib\\mpl-data\\fonts\\ttf\\msyh.ttf"  # 请替换为实际路径
    font = ImageFont.truetype(font_path, bbox_labelstr['font_size'])

    # 画框和文字
    for obj in root.iter('object'):
        bbox_label = obj.find('name').text
        bbox_top_left_x = int(obj.find('bndbox').find('xmin').text)
        bbox_top_left_y = int(obj.find('bndbox').find('ymin').text)
        bbox_bottom_right_x = int(obj.find('bndbox').find('xmax').text)
        bbox_bottom_right_y = int(obj.find('bndbox').find('ymax').text)

        draw.rectangle([(bbox_top_left_x, bbox_top_left_y), (bbox_bottom_right_x, bbox_bottom_right_y)],
                       outline=bbox_color, width=bbox_thickness)

        draw.text((bbox_top_left_x + bbox_labelstr['offset_x'], bbox_top_left_y + bbox_labelstr['offset_y']),
                  bbox_label, font=font, fill=bbox_color_str)

    img_bgr = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)

    # 保存图像
    cv2.imwrite(result_path + "\\{}.jpg".format(img_names[i]), img_bgr)

下面是matplotlib+cv2版代码

python 复制代码
# 数据集可视化
import cv2
import os
import matplotlib.pyplot as plt
import xml.etree.ElementTree as ET

# 设置 Matplotlib 使用的字体为黑体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False 

imgs_path = 'E:\\test\\tianjingulou\\img'
anns_path = 'E:\\test\\tianjingulou\\xml'
 
img_names = set([os.path.splitext(i)[0] for i in os.listdir(imgs_path)])
ann_names = set([os.path.splitext(i)[0] for i in os.listdir(anns_path)])
img_names = list(img_names)
ann_names = list(ann_names)

for i in range(len(img_names)):
    img_path = os.path.join(imgs_path, img_names[i] + ".jpg")
    img_bgr = cv2.imread(img_path)
 
    xml_path = os.path.join(anns_path, ann_names[i] + ".xml")
 
    xml_inf = open(xml_path, encoding='utf-8')
    tree = ET.parse(xml_inf)
    root = tree.getroot()
 
# 框可视化配置
    bbox_color = (255, 129, 0)  # 框的颜色
    bbox_thickness = 2  # 框的线宽
 
# 框类别文字
    bbox_labelstr = {
        'font_size': 1,  # 字体大小
        'font_thickness': 2,  # 字体粗细
        'offset_x': 0,  # X 方向,文字偏移距离,向右为正
        'offset_y': -10,  # Y 方向,文字偏移距离,向下为正
    }
# 画框
    for obj in root.iter('object'):  # 一个object代表一个标注物体
 
        # 框的类别
        bbox_label = obj.find('name').text
 
        # 框的两点坐标
        # 左上角坐标
        bbox_top_left_x = int(obj.find('bndbox').find('xmin').text)
        bbox_top_left_y = int(obj.find('bndbox').find('ymin').text)
        # 右下角坐标
        bbox_bottom_right_x = int(obj.find('bndbox').find('xmax').text)
        bbox_bottom_right_y = int(obj.find('bndbox').find('ymax').text)
 
        # 画矩形:画框
        img_bgr = cv2.rectangle(img_bgr, (bbox_top_left_x, bbox_top_left_y), (bbox_bottom_right_x, bbox_bottom_right_y),
                            bbox_color, bbox_thickness)

        # 写框类别文字:图片,文字字符串,文字左上角坐标,字体,字体大小,颜色,字体粗细
        img_bgr = cv2.putText(img_bgr, bbox_label, (
            bbox_top_left_x + bbox_labelstr['offset_x'],
            bbox_top_left_y + bbox_labelstr['offset_y']),
                          cv2.FONT_HERSHEY_SIMPLEX, bbox_labelstr['font_size'], bbox_color,
                          bbox_labelstr['font_thickness'])
 
    cv2.imwrite("E:\\test\\tianjingulou\\{}.jpg".format(img_names[i]), img_bgr)

写在最后,matplotlib的方式应该也有解决的办法,也可能是我的环境问题,提供这两种方式大家各取所需,下面这种方式是我从一位博主那里拷贝来稍加改动的,但是我找不到出处了,如有侵权请联系我删除。

----------------------------------------------华丽分割-------------------------------------------------

追加一种类似的写法,这个是宋体,字体可以酌情替换,亲测可用

python 复制代码
import cv2
import os
import matplotlib.pyplot as plt
import xml.etree.ElementTree as ET
import numpy as np


# 导入 PIL 库
import PIL.Image
import PIL.ImageDraw
import PIL.ImageFont


data_path = os.path.join("E:\\test\\tianjingulou")
imgs_path = os.path.join(data_path, "img")
anns_path = os.path.join(data_path, "xml")

# 获取图像名称和标注名称
img_names = set(os.path.splitext(i)[0] for i in os.listdir(imgs_path))
ann_names = set(os.path.splitext(i)[0] for i in os.listdir(anns_path))
img_names = list(img_names)
ann_names = list(ann_names)

# 遍历所有图像
for i, img_name in enumerate(img_names):

    # 读取图像
    img_bgr = cv2.imread(os.path.join(imgs_path, img_name + ".jpg"))

    # 读取标注
    xml_path = os.path.join(anns_path, img_name + ".xml")
    xml_inf = open(xml_path, encoding='utf-8')
    tree = ET.parse(xml_inf)
    root = tree.getroot()

    # 画框
    for obj in root.iter('object'):

        # 获取框的类别
        bbox_label = obj.find('name').text

        # 获取框的两点坐标
        bbox_top_left_x = int(obj.find('bndbox').find('xmin').text)
        bbox_top_left_y = int(obj.find('bndbox').find('ymin').text)
        bbox_bottom_right_x = int(obj.find('bndbox').find('xmax').text)
        bbox_bottom_right_y = int(obj.find('bndbox').find('ymax').text)

        # 画矩形
        img_bgr = cv2.rectangle(img_bgr, (bbox_top_left_x, bbox_top_left_y), (bbox_bottom_right_x, bbox_bottom_right_y),
                               (255, 129, 0), 2)

        # 写框类别文字
        # 转换为 PIL 图像
        img_pil = PIL.Image.fromarray(img_bgr)

        # 使用 PIL 绘制文本
        font = PIL.ImageFont.truetype("simsun.ttc", 16)
        draw = PIL.ImageDraw.Draw(img_pil)
        draw.text((bbox_top_left_x, bbox_top_left_y - 18), bbox_label, font=font, fill=(255, 129, 0))

        # 直接使用 PIL 图像
        img_bgr = np.array(img_pil)

    # 保存图像
    cv2.imwrite(data_path + "\\{}.jpg".format(img_name), img_bgr)
相关推荐
SEO-狼术7 小时前
Connect Directly to Oracle XML Data
xml·数据库·oracle
YSoup12 小时前
2025年目前最新版本Android Studio自定义xml预览的屏幕分辨率
android·xml·android studio
abcnull2 天前
mybatis的mapper对应的xml写法
xml·sql·spring·mybatis·mapper
Blue桃之夭夭2 天前
HTML、XML、JSON 是什么?有什么区别?又是做什么的?
xml·html·json
小于村2 天前
pom.xml 文件中配置你项目中的外部 jar 包打包方式
xml·java·jar
扶风呀2 天前
pom.xml中标签详解_
xml
Blue桃之夭夭3 天前
Python进阶【四】:XML和JSON文件处理
xml·python·json
米粉03053 天前
Ajax(Asynchronous JavaScript and XML)
xml·javascript·ajax
ecoolper4 天前
maven项目编译时复制xml到classes目录方案
xml·java·maven
王有品5 天前
Spring 核心配置文件(spring.xml)构建指南
xml·java·spring