import cv2 import numpy as np from PIL import Image, ImageDraw, ImageFont import os class ChineseTextRenderer: def __init__(self, font_path=None): self.font_cache = {} self.font_path = font_path def put_text(self, img, text, position, font_size=20, color=(0, 255, 0)): """安全的中文文本绘制函数""" # 输入验证 if img is None: raise ValueError("输入图像不能为None") if not isinstance(img, np.ndarray): raise TypeError(f"输入图像必须是numpy数组,实际是{type(img)}") if len(img.shape) != 3 or img.shape[2] != 3: # 尝试转换 if len(img.shape) == 2: img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) elif len(img.shape) == 3 and img.shape[2] == 4: img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) else: raise ValueError(f"不支持的图像格式,shape={img.shape}") try: # BGR转RGB img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) pil_img = Image.fromarray(img_rgb) draw = ImageDraw.Draw(pil_img) # 获取字体 font = self._get_font(font_size) # 颜色转换:BGR到RGB rgb_color = color[::-1] # 绘制文本 draw.text(position, text, font=font, fill=rgb_color) # RGB转BGR return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) except Exception as e: print(f"中文渲染失败: {e},使用英文后备") # 后备方案:使用OpenCV绘制英文 cv2.putText(img, text, position, cv2.FONT_HERSHEY_SIMPLEX, font_size / 30, color, 2) return img def _get_font(self, size): """获取字体对象,带缓存""" if size in self.font_cache: return self.font_cache[size] # 查找字体文件 font_paths = [] if self.font_path and os.path.exists(self.font_path): font_paths.append(self.font_path) # 添加常用字体路径 font_paths.extend([ "simhei.ttf", "msyh.ttc", "C:/Windows/Fonts/simhei.ttf", "C:/Windows/Fonts/msyh.ttc", "C:/Windows/Fonts/Deng.ttf", "C:/Windows/Fonts/simsun.ttc", ]) # 遍历所有可能的字体路径 font = None for path in font_paths: if os.path.exists(path): try: font = ImageFont.truetype(path, size, encoding="utf-8") print(f"加载字体: {path}") break except Exception as e: continue # 如果找不到字体,尝试创建默认字体 if font is None: try: font = ImageFont.load_default() # 调整默认字体大小 font = ImageFont.truetype("arial.ttf", size) except: # 最后手段:使用PIL的默认字体 font = ImageFont.load_default() self.font_cache[size] = font return font def ensure_image_valid(img, default_size=(640, 480)): """确保图像有效,如果无效则创建默认图像""" if img is None or not isinstance(img, np.ndarray) or img.size == 0: print("创建默认图像...") img = np.zeros((default_size[0], default_size[1], 3), dtype=np.uint8) img.fill(50) # 添加一些参考线 h, w = img.shape[:2] cv2.line(img, (0, 0), (w, h), (0, 255, 0), 1) cv2.line(img, (w, 0), (0, h), (0, 255, 0), 1) cv2.circle(img, (w // 2, h // 2), min(w, h) // 4, (255, 0, 0), 2) return img