添加opencv支持中文显示,添加自定义中文字体路径配置, opencv.imshow窗口自动最大化功能
This commit is contained in:
parent
8ef2ba9130
commit
cc04524164
@ -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
153
main.py
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user