添加opencv支持中文显示,添加自定义中文字体路径配置, opencv.imshow窗口自动最大化功能

This commit is contained in:
haotian 2025-09-30 11:55:16 +08:00
parent 8ef2ba9130
commit cc04524164
2 changed files with 121 additions and 39 deletions

View File

@ -44,4 +44,9 @@ logging:
level: "INFO" # DEBUG, INFO, WARNING, ERROR
file: "face_recognition.log"
max_bytes: 10485760 # 10MB
backup_count: 5
backup_count: 5
# 中文字体设置
display:
font_path: "/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf"

153
main.py
View File

@ -12,6 +12,7 @@ from compreface import CompreFace
from compreface.service import RecognitionService, DetectionService
import time
from collections import defaultdict
from PIL import Image, ImageDraw, ImageFont
class FaceRecognitionSystem:
@ -66,6 +67,12 @@ class FaceRecognitionSystem:
self.last_fps_time = time.time()
self.fps_counter = 0
# 加载中文字体
self.font_path = self._get_chinese_font()
self.font_small = ImageFont.truetype(self.font_path, 20)
self.font_medium = ImageFont.truetype(self.font_path, 24)
self.font_large = ImageFont.truetype(self.font_path, 28)
self.logger.info("人脸识别系统初始化完成")
def _setup_logging(self):
@ -95,6 +102,51 @@ class FaceRecognitionSystem:
self.logger.addHandler(file_handler)
self.logger.addHandler(console_handler)
def _get_chinese_font(self) -> str:
"""获取中文字体路径"""
import platform
import os
system = platform.system()
# Windows系统
if system == "Windows":
font_paths = [
"C:/Windows/Fonts/msyh.ttc", # 微软雅黑
"C:/Windows/Fonts/simhei.ttf", # 黑体
"C:/Windows/Fonts/simsun.ttc", # 宋体
]
# macOS系统
elif system == "Darwin":
font_paths = [
"/System/Library/Fonts/PingFang.ttc", # 苹方
"/System/Library/Fonts/STHeiti Medium.ttc", # 黑体
"/Library/Fonts/Arial Unicode.ttf",
]
# Linux系统
else:
font_paths = [
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
]
# 查找可用的字体
for font_path in font_paths:
if os.path.exists(font_path):
self.logger.info(f"使用中文字体: {font_path}")
return font_path
# 如果没找到,尝试使用配置文件中的字体路径
if 'font_path' in self.config.get('display', {}):
custom_font = self.config['display']['font_path']
if os.path.exists(custom_font):
self.logger.info(f"使用自定义字体: {custom_font}")
return custom_font
# 默认使用一个基本字体(不支持中文,但至少不会报错)
self.logger.warning("未找到中文字体,将使用默认字体(可能无法显示中文)")
return "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
def _init_compreface(self):
"""初始化CompreFace SDK"""
cf_config = self.config['compreface']
@ -221,6 +273,20 @@ class FaceRecognitionSystem:
return elapsed >= cooldown
def cv2_add_chinese_text(self, img: np.ndarray, text: str, position: Tuple[int, int],
font: ImageFont.FreeTypeFont, text_color: Tuple[int, int, int]) -> np.ndarray:
"""在OpenCV图像上添加中文文本"""
# 转换为PIL图像
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
# 绘制文本
draw.text(position, text, font=font, fill=text_color)
# 转换回OpenCV格式
img = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
return img
def draw_info_on_frame(self, frame: np.ndarray) -> np.ndarray:
"""在帧上绘制检测和识别信息"""
display_frame = frame.copy()
@ -255,21 +321,20 @@ class FaceRecognitionSystem:
# 准备文本
text_lines = [
f"Name: {name}",
f"Role: {role}",
f"Similarity: {similarity:.2%}"
f"姓名: {name}",
f"角色: {role}",
f"相似度: {similarity:.2%}"
]
# 计算文本背景框
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.6
font_thickness = 2
line_height = 35
padding = 10
line_height = 30
# 绘制文本背景
# 计算所需的背景高度
bg_height = len(text_lines) * line_height + padding * 2
bg_y_start = max(0, y_min - bg_height - 10)
# 绘制文本背景
cv2.rectangle(
display_frame,
(x_min, bg_y_start),
@ -285,39 +350,34 @@ class FaceRecognitionSystem:
2
)
# 绘制文本
# 使用PIL绘制中文文本
for i, text in enumerate(text_lines):
y_pos = bg_y_start + padding + (i + 1) * line_height - 5
cv2.putText(
y_pos = bg_y_start + padding + i * line_height
display_frame = self.cv2_add_chinese_text(
display_frame,
text,
(x_min + padding, y_pos),
font,
font_scale,
(255, 255, 255),
font_thickness
self.font_medium,
(255, 255, 255)
)
# 绘制状态信息面板
panel_height = 180
panel_height = 200
panel_bg = np.zeros((panel_height, w, 3), dtype=np.uint8)
panel_bg[:] = (40, 40, 40)
# 状态信息
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.5
font_thickness = 1
text_color = (255, 255, 255)
y_offset = 25
x_offset = 10
y_offset = 30
x_offset = 15
line_spacing = 30
status_texts = [
f"FPS: {self.display_info['fps']:.1f}",
f"Frame: {self.display_info['frame_count']}",
f"Quality: {self.display_info['quality']:.1f}",
f"Face Detected: {'Yes' if self.display_info['face_detected'] else 'No'}",
f"Robot Speaking: {'Yes' if self.robot_status['is_speaking'] else 'No'}",
f"Robot Thinking: {'Yes' if self.robot_status['is_thinking'] else 'No'}",
f"帧率: {self.display_info['fps']:.1f} FPS",
f"帧数: {self.display_info['frame_count']}",
f"质量: {self.display_info['quality']:.1f}",
f"检测到人脸: {'' if self.display_info['face_detected'] else ''}",
f"机器人说话: {'' if self.robot_status['is_speaking'] else ''}",
f"机器人思考: {'' if self.robot_status['is_thinking'] else ''}",
]
# 如果人脸持续出现,显示倒计时
@ -325,17 +385,16 @@ class FaceRecognitionSystem:
elapsed = (datetime.now() - self.face_present_start).total_seconds()
face_duration = self.config['face_detection']['face_present_duration']
remaining = max(0, face_duration - elapsed)
status_texts.append(f"Recognition in: {remaining:.1f}s")
status_texts.append(f"识别倒计时: {remaining:.1f}")
# 使用PIL绘制中文状态文本
for i, text in enumerate(status_texts):
cv2.putText(
panel_bg = self.cv2_add_chinese_text(
panel_bg,
text,
(x_offset, y_offset + i * 25),
font,
font_scale,
text_color,
font_thickness
(x_offset, y_offset + i * line_spacing),
self.font_small,
(255, 255, 255)
)
# 将面板添加到画面底部
@ -442,8 +501,26 @@ class FaceRecognitionSystem:
self.logger.info("开始处理视频流")
# 创建显示窗口
cv2.namedWindow('Face Recognition System', cv2.WINDOW_NORMAL)
# 创建显示窗口并最大化
window_name = 'Face Recognition System'
cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
# 设置窗口为全屏或最大化
# 方法1: 全屏模式
# cv2.setWindowProperty(window_name, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
# 方法2: 最大化窗口(推荐)
cv2.setWindowProperty(window_name, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_NORMAL)
# 获取屏幕分辨率并设置窗口大小
try:
import screeninfo
screen = screeninfo.get_monitors()[0]
cv2.resizeWindow(window_name, screen.width, screen.height)
cv2.moveWindow(window_name, 0, 0)
except:
# 如果screeninfo不可用,尝试设置一个较大的窗口
cv2.resizeWindow(window_name, 1920, 1080)
self.logger.warning("无法获取屏幕分辨率,使用默认窗口大小")
try:
while True:
@ -585,7 +662,7 @@ class FaceRecognitionSystem:
# 绘制信息并显示
display_frame = self.draw_info_on_frame(frame)
cv2.imshow('Face Recognition System', display_frame)
cv2.imshow(window_name, display_frame)
# 检查键盘输入
key = cv2.waitKey(1) & 0xFF