Python高效绘制中文文本到视频流帧的优化方法

引言

在视频流分析中,我们经常需要在每一帧上绘制检测框和对应的中文标签。然而,直接使用 OpenCV 绘制中文存在一定的局限性,因为 OpenCV 的 cv2.putText 不支持中文字符。通常我们会选择结合 PIL 来完成中文绘制,但这会涉及到 OpenCV 图像和 PIL 图像的频繁转换,尤其是在处理高分辨率图像时,这种转换非常耗时,可能导致性能瓶颈。

为了解决这个问题,我将介绍一种 Python高效中文字符绘制方法:通过预渲染中文标签为纹理并缓存起来,再将纹理粘贴到图像上。这种方法避免了每帧都实时渲染中文字符,大幅提升了性能,非常适合实时视频流分析场景。

核心思路

  1. 预渲染中文文本:使用 PIL 将中文文本渲染成带透明背景的纹理图像,并将纹理缓存到字典中,避免重复渲染相同的文本。
  2. 纹理粘贴:将预渲染的纹理直接粘贴到 OpenCV 图像中,利用透明度实现无缝融合。
  3. 批量绘制:通过缓存机制和纹理粘贴优化整个绘制过程。

代码实现

import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np


class DetectionDrawer:
    def __init__(self, font_path: str, font_size: int):
        """
        初始化绘制类,加载中文字体并创建缓存。
        
        :param font_path: 字体文件路径(支持中文的 TTF 文件)。
        :param font_size: 字体大小。
        """
        self.font = ImageFont.truetype(font_path, font_size)
        self.text_texture_cache = {}  # 用于缓存已渲染的中文标签纹理

    def create_text_texture(self, text: str, color: tuple):
        """
        创建中文文本的纹理并缓存。
        
        :param text: 要渲染的文本内容。
        :param color: 文本颜色 (R, G, B)。
        :return: 预渲染的文本纹理(NumPy 数组)。
        """
        if text in self.text_texture_cache:
            return self.text_texture_cache[text]

        # 计算文本尺寸
        bbox = self.font.getbbox(text)
        text_width = bbox[2] - bbox[0]
        text_height = bbox[3] - bbox[1]

        # 创建透明背景的图像
        text_img = Image.new("RGBA", (text_width, text_height), (0, 0, 0, 0))
        draw = ImageDraw.Draw(text_img)
        draw.text((0, 0), text, font=self.font, fill=color + (255,))  # 带透明度

        # 转换为 NumPy 格式并缓存
        text_texture = np.array(text_img)
        self.text_texture_cache[text] = text_texture
        return text_texture

    def paste_text_texture(self, img: np.ndarray, position: tuple, text_texture: np.ndarray):
        """
        将预渲染的文本纹理粘贴到 OpenCV 图像上。
        
        :param img: OpenCV 图像。
        :param position: 粘贴位置 (x, y)。
        :param text_texture: 文本纹理(带透明通道的 NumPy 数组)。
        :return: 添加文本后的图像。
        """
        x, y = position
        h, w, _ = text_texture.shape
        h_img, w_img, _ = img.shape

        # 限制粘贴区域,避免超出图像边界
        w = min(w, w_img - x)
        h = min(h, h_img - y)

        if w <= 0 or h <= 0:  # 如果超出边界,直接返回
            return img

        alpha_channel = text_texture[:h, :w, 3] / 255.0  # 透明度通道
        rgb_texture = text_texture[:h, :w, :3]           # RGB 通道

        # 粘贴纹理
        img[y:y + h, x:x + w, :] = (
            (1 - alpha_channel[:, :, None]) * img[y:y + h, x:x + w, :]
            + alpha_channel[:, :, None] * rgb_texture
        )
        return img

    def draw_detections(self, frame: np.ndarray, detections: list):
        """
        批量绘制检测框和中文标签。
        
        :param frame: 输入帧(OpenCV 格式)。
        :param detections: 检测信息 [(bbox, label_text, color)]。
                          bbox 格式为 (x1, y1, x2, y2)。
        :return: 绘制后的帧。
        """
        for bbox, label_text, color in detections:
            x1, y1, x2, y2 = bbox

            # 绘制检测框
            cv2.rectangle(frame, (x1, y1), (x2, y2), color, thickness=2)

            # 创建文本纹理
            text_texture = self.create_text_texture(label_text, color[::-1])  # BGR -> RGB

            # 计算文本位置
            text_h, text_w, _ = text_texture.shape
            text_x, text_y = x1, y1 - text_h if y1 > text_h else y1 + 2

            # 粘贴文本纹理
            frame = self.paste_text_texture(frame, (text_x, text_y), text_texture)

        return frame

使用方法

  1. 加载字体文件:确保提供一个支持中文字符的字体文件(如 simhei.ttf 或其他 TTF 文件)。

  2. 实例化类

    drawer = DetectionDrawer(font_path="simhei.ttf", font_size=20)
    
  3. 调用绘制方法

    # 示例检测框和标签
    detections = [
        [(50, 50, 200, 200), "类别1", (0, 255, 0)],
        [(300, 300, 450, 450), "类别2", (255, 0, 0)]
    ]
    
    # 绘制检测框和中文标签
    frame = cv2.imread("example.jpg")
    frame_with_detections = drawer.draw_detections(frame, detections)
    

在这里插入图片描述

优势分析

  1. 性能优化
    • 文本纹理的缓存机制避免重复渲染,大幅减少 PIL 的调用次数。
    • 结合 OpenCV 和 PIL 的长处,既能高效处理图像,又能支持中文绘制。
  2. 易用性
    • 支持多种字体、颜色和大小的中文标签渲染。
    • 使用简单,可直接集成到检测或跟踪系统中。
  3. 适用场景
    • 实时视频流分析。
    • 各类目标检测任务(如安全监控、自动驾驶等)。

总结

通过将中文标签预渲染为纹理并缓存起来,我们成功实现了一种高效的中文绘制方法,特别适合实时视频流分析场景。这种方法不仅提升了性能,还简化了代码逻辑,非常值得在实际项目中推广使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值