限制识别角度,修改引导图片

This commit is contained in:
Tian jianyong 2025-12-18 14:14:32 +08:00
parent 5b81d6ae95
commit a6f91fed23
6 changed files with 68 additions and 18 deletions

View File

@ -8,6 +8,7 @@
### 1. 人脸识别
- **实时检测**:基于 CompreFace API 进行高精度人脸检测
- **正脸检测**:使用姿态检测技术,只识别正面人脸,过滤侧脸、抬头或低头
- **身份识别**:自动识别员工和访客,支持相似度阈值配置
- **防重复识别**:智能冷却机制,避免短时间内重复识别同一人
- **质量评估**:使用 Laplacian 方差评估图像清晰度
@ -128,6 +129,15 @@ camera:
height: 720
fps: 30
# 人脸检测配置
face_detection:
frame_interval: 10 # 检测帧间隔(每N帧检测一次)
quality_threshold: 10 # 图像质量阈值(Laplacian方差)
min_face_size: 80 # 最小人脸尺寸(像素)
face_present_duration: 2.0 # 持续出现时长(秒)才触发识别
max_yaw: 30.0 # 最大允许的偏航角(度),超过此角度视为侧脸
max_pitch: 30.0 # 最大允许的俯仰角(度),超过此角度视为抬头或低头
# 人脸识别配置
face_recognition:
recognition_cooldown: 20.0 # 识别冷却时间(秒)
@ -290,6 +300,8 @@ kanda-robot-facial-recognition/
- `quality_threshold`: 图像质量阈值,建议 10-50
- `min_face_size`: 最小人脸尺寸(像素),建议 60-100
- `face_present_duration`: 持续出现时长(秒),建议 1.5-3.0
- `max_yaw`: 最大允许的偏航角(度),超过此角度视为侧脸,建议 20-40
- `max_pitch`: 最大允许的俯仰角(度),超过此角度视为抬头或低头,建议 20-40
- `stranger_threshold`: 陌生人阈值,建议 0.95-0.99
- `recognition_cooldown`: 识别冷却时间(秒),建议 15-30
@ -377,7 +389,14 @@ camera:
3. 确保光线充足
4. 在 CompreFace 中添加更多训练照片
### Q6: 系统服务无法启动
### Q6: 侧脸也被识别了
**A:**
1. 调整 `max_yaw``max_pitch` 参数,降低角度阈值
2. 默认设置为 ±30 度,可改为 ±20 度提高严格程度
3. 检查 CompreFace 服务是否支持 pose 插件
4. 查看日志中的角度检查信息进行调试
### Q7: 系统服务无法启动
**A:**
1. 检查服务文件路径配置
2. 确认 Python 环境和依赖
@ -455,6 +474,11 @@ python preview_qrcode.py
## 更新日志
### v1.1.0 (2025-12-18)
- ✅ 新增正脸检测功能,基于姿态检测技术过滤侧脸
- ✅ 添加人脸角度阈值配置max_yaw, max_pitch
- ✅ 优化人脸识别准确性,适用于门禁场景
### v1.0.0 (2025-12-03)
- ✅ 完整的人脸检测和识别功能
- ✅ WebSocket 双向通信

View File

@ -42,6 +42,8 @@ face_detection:
quality_threshold: 10 # 图像质量阈值(Laplacian方差)
min_face_size: 80 # 最小人脸尺寸(像素)
face_present_duration: 2.0 # 持续出现时长(秒)才触发识别
max_yaw: 30.0 # 最大允许的偏航角(度),超过此角度视为侧脸
max_pitch: 30.0 # 最大允许的俯仰角(度),超过此角度视为抬头或低头
# 人脸识别配置
face_recognition:

View File

@ -683,16 +683,16 @@ class FaceRecognitionSystem:
try:
import screeninfo
screen = screeninfo.get_monitors()[0]
canvas_width = int(screen.width * 0.8)
canvas_height = int(screen.height * 0.8)
x_pos = (screen.width - canvas_width) // 2
y_pos = (screen.height - canvas_height) // 2
canvas_width = int(screen.width)
canvas_height = int(screen.height)
x_pos = 0
y_pos = 0
except Exception as e:
self.logger.warning(f"无法获取屏幕信息,使用默认尺寸: {e}")
canvas_width = max(qr_width * 2, 1400)
canvas_height = max(qr_height, 900)
x_pos = 100
y_pos = 60
canvas_width = max(qr_width * 2, 1920)
canvas_height = max(qr_height, 1080)
x_pos = 0
y_pos = 0
rendered = self._build_qrcode_instruction_canvas(qr_image, (canvas_width, canvas_height))
if rendered is None:
@ -708,6 +708,9 @@ class FaceRecognitionSystem:
cv2.resizeWindow(self.qrcode_window_name, canvas_width, canvas_height)
cv2.moveWindow(self.qrcode_window_name, x_pos, y_pos)
# 设置窗口全屏显示
cv2.setWindowProperty(self.qrcode_window_name, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
cv2.imshow(self.qrcode_window_name, rendered)
# 设置窗口置顶
@ -1242,19 +1245,40 @@ class FaceRecognitionSystem:
# 将帧编码为JPEG
_, img_encoded = cv2.imencode('.jpg', frame)
# 调用CompreFace检测API
result = self.detection_service.detect(img_encoded.tobytes())
# 调用CompreFace检测API启用pose插件
result = self.detection_service.detect(
img_encoded.tobytes(),
face_plugins="pose"
)
if result and 'result' in result and len(result['result']) > 0:
faces = result['result']
# 过滤掉太小的人脸
min_size = self.config['face_detection']['min_face_size']
valid_faces = [
face for face in faces
if face['box']['x_max'] - face['box']['x_min'] >= min_size
and face['box']['y_max'] - face['box']['y_min'] >= min_size
]
valid_faces = []
# 获取角度阈值
max_yaw = self.config['face_detection'].get('max_yaw', 30.0)
max_pitch = self.config['face_detection'].get('max_pitch', 30.0)
for face in faces:
# 检查人脸尺寸
face_width = face['box']['x_max'] - face['box']['x_min']
face_height = face['box']['y_max'] - face['box']['y_min']
if face_width >= min_size and face_height >= min_size:
# 检查人脸角度
pose = face.get('pose', {})
yaw = pose.get('yaw', 0.0)
pitch = pose.get('pitch', 0.0)
# 判断是否为正脸
if abs(yaw) <= max_yaw and abs(pitch) <= max_pitch:
valid_faces.append(face)
self.logger.debug(f"人脸角度检查通过: yaw={yaw:.1f}°, pitch={pitch:.1f}°")
else:
self.logger.debug(f"人脸角度超出范围,跳过: yaw={yaw:.1f}°(阈值±{max_yaw}°), pitch={pitch:.1f}°(阈值±{max_pitch}°)")
if valid_faces:
# 返回第一个(最大的)人脸

View File

@ -326,8 +326,8 @@ def main():
cv2.destroyAllWindows()
# Save for verification
cv2.imwrite("preview_qrcode_sota.jpg", canvas)
print("Saved preview to preview_qrcode_sota.jpg")
cv2.imwrite("preview_qrcode_sota.png", canvas)
print("Saved preview to preview_qrcode_sota.png")
if __name__ == "__main__":
main()

BIN
preview_qrcode_sota.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

View File

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 264 KiB