最近写的一个 DEMO 中,需要把 [[OpenCV]] 处理后的视频流直接通过 [[imshow]] 显示,并且要在左上角显示对应的结果给客户演示。测试时发现用 [[putText]] 加入中文会导致乱码。
putText 乱码
看了官方文档发现使用 putText
中文乱码问题是因为在 OpenCV 中使用的是 Hershey 字体,这类字体是不支持中文的。
import cv2
def main(rtsp_url:str): # 连接 RTSP 视频流 cap = cv2.VideoCapture(rtsp_url)
while True: ret, frame = cap.read() if not ret: print("无法读取视频流") break
# 左上角添加中文 cv2.putText(frame, "演示 Demo", (30, 50), # 位置坐标 cv2.FONT_HERSHEY_SIMPLEX,# 字体 1, # 字体大小 (0, 255, 0), # 颜色 (BGR) 2) # 线条粗细
# 显示结果 cv2.imshow("Demo Preview", frame)
# 按 'q' 退出 if cv2.waitKey(1) & 0xFF == ord('q'): break
# 释放资源 cap.release() cv2.destroyAllWindows()
if __name__ == "__main__": rtsp_url = "rtsp://192.168.1.100:554/live" main(rtsp_url)
Pillow 介入解决
尝试使用 [[pillow]] 库中 [[Image]] 模块解决:
import numpy as npfrom PIL import Image, ImageDraw, ImageFont
def add_chinese_text( img: np.ndarray, text: str, position: tuple, font_path: str, font_size: int = 32, text_color: str = "black",) -> np.ndarray:
# 先把 OpenCV 图像转换为 PIL 图像 img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 创建 PIL 绘图对象,并设置字体和大小,然后绘制文字 draw = ImageDraw.Draw(img_pil) font = ImageFont.truetype(font_path, font_size) draw.text(position, text, font=font, fill=text_color)
# 把 PIL 图像转换回 OpenCV 格式 return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
然后把最初代码中的 cv2.putText
替换为 add_chinese_text
即可:
# 添加中文文字frame = add_chinese_text(frame, "演示 Demo", font_path="STHeiti Light.ttc", position=(30, 50), font_size=32, text_color="blue")
需要注意的是 font_path 传递的字体在对应系统中必须存在。比如 [[macOS]] 中可以使用 STHeiti Light.ttc
字体,在 [[Ubuntu]] 可以使用 NotoSansCJK-Regular.ttc
字体(也支持传递完整的路径和相对路径)。
到此,中文应该可以正常显示了,下面是完整代码:
import cv2import numpy as npfrom PIL import Image, ImageDraw, ImageFont
def add_chinese_text( img: np.ndarray, text: str, position: tuple, font_path: str, font_size: int = 32, text_color: str = "black",) -> np.ndarray:
# 先把 OpenCV 图像转换为 PIL 图像 img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 创建 PIL 绘图对象,并设置字体和大小,然后绘制文字 draw = ImageDraw.Draw(img_pil) font = ImageFont.truetype(font_path, font_size) draw.text(position, text, font=font, fill=text_color)
# 把 PIL 图像转换回 OpenCV 格式 return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
def main(rtsp_url:str): # 连接 RTSP 视频流 cap = cv2.VideoCapture(rtsp_url)
while True: ret, frame = cap.read() if not ret: print("无法读取视频流") break
# 左上角添加中文 frame = add_chinese_text(frame, "演示 Demo", font_path="STHeiti Light.ttc", position=(30, 50), font_size=32, text_color="blue") # 显示结果 cv2.imshow("Demo Preview", frame)
# 按 'q' 退出 if cv2.waitKey(1) & 0xFF == ord('q'): break
# 释放资源 cap.release() cv2.destroyAllWindows()
if __name__ == "__main__": rtsp_url = "rtsp://192.168.1.100:554/live" main(rtsp_url)
最后
如果文字是固定不变的,可以先用 Image.new
创建一个空白图片,然后通过 [[ImageDraw]] 把文字绘制好,这样只需要把图片叠加到 frame 上即可,不需要每一帧都重复操作。