Files
momentry_core/scripts/extract_female_faces.py
Warren 8f05a7c188 feat: update Python processors and add utility scripts
- Update ASR, face, OCR, pose processors
- Add release pre-flight check script
- Add synonym generation, chunk processing scripts
- Add face recognition, stamp search utilities
2026-04-30 15:07:49 +08:00

358 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
提取女性最多的畫面並標記人臉
"""
import cv2
import numpy as np
import json
import os
from datetime import datetime
def draw_female_faces(image_path, frame_number, output_dir="/tmp/female_faces"):
"""在圖像上標記女性人臉"""
# 創建輸出目錄
os.makedirs(output_dir, exist_ok=True)
# 讀取圖像
image = cv2.imread(image_path)
if image is None:
print(f"❌ 無法讀取圖像: {image_path}")
return None
# 從數據庫獲取女性人臉信息
import psycopg2
conn = psycopg2.connect(
host="localhost",
port=5432,
database="momentry",
user="accusys",
password="accusys",
)
cursor = conn.cursor()
cursor.execute(
"""
SELECT x, y, width, height, confidence,
(attributes->>'age')::numeric as age
FROM face_detections
WHERE frame_number = %s
AND attributes->>'gender' = 'female'
ORDER BY confidence DESC
""",
(frame_number,),
)
female_faces = cursor.fetchall()
cursor.close()
conn.close()
if not female_faces:
print(f"❌ 在幀 {frame_number} 中未找到女性人臉")
return None
print(f"✅ 在幀 {frame_number} 中找到 {len(female_faces)} 個女性人臉")
# 複製圖像用於標記
marked_image = image.copy()
# 標記每個人臉
for i, (x, y, w, h, confidence, age) in enumerate(female_faces):
# 繪製邊界框(粉色表示女性)
color = (255, 105, 180) # 粉色
thickness = 3
# 繪製矩形邊界框
cv2.rectangle(marked_image, (x, y), (x + w, y + h), color, thickness)
# 添加標籤
label = f"{i + 1}"
if age:
label += f" ({int(age)}歲)"
label += f" {confidence:.1%}"
# 計算標籤位置
label_size, baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2)
label_y = max(y - 10, label_size[1] + 10)
# 繪製標籤背景
cv2.rectangle(
marked_image,
(x, label_y - label_size[1] - 10),
(x + label_size[0] + 10, label_y + 5),
color,
-1, # 填充
)
# 繪製標籤文字
cv2.putText(
marked_image,
label,
(x + 5, label_y - 5),
cv2.FONT_HERSHEY_SIMPLEX,
0.7,
(255, 255, 255), # 白色文字
2,
)
print(
f" 人臉 {i + 1}: 位置 [{x},{y},{w},{h}], 置信度 {confidence:.1%}, 年齡 {int(age) if age else '未知'}"
)
# 添加標題
title = f"女性最多的畫面 - 幀 {frame_number} - {len(female_faces)} 個女性"
title_size, _ = cv2.getTextSize(title, cv2.FONT_HERSHEY_SIMPLEX, 1.2, 3)
# 繪製標題背景
cv2.rectangle(
marked_image,
(10, 10),
(10 + title_size[0] + 20, 10 + title_size[1] + 20),
(0, 0, 0), # 黑色背景
-1,
)
# 繪製標題
cv2.putText(
marked_image,
title,
(20, 20 + title_size[1]),
cv2.FONT_HERSHEY_SIMPLEX,
1.2,
(255, 255, 255), # 白色文字
3,
)
# 添加時間戳信息
timestamp = frame_number / 59.94 # 假設 59.94 FPS
minutes = int(timestamp // 60)
seconds = int(timestamp % 60)
time_info = f"時間: {minutes:02d}:{seconds:02d}"
cv2.putText(
marked_image,
time_info,
(20, 60 + title_size[1]),
cv2.FONT_HERSHEY_SIMPLEX,
0.8,
(200, 200, 200), # 淺灰色
2,
)
# 保存標記後的圖像
output_path = os.path.join(output_dir, f"female_faces_frame_{frame_number}.jpg")
cv2.imwrite(output_path, marked_image)
print(f"✅ 已保存標記圖像: {output_path}")
# 創建縮略圖(便於查看)
height, width = marked_image.shape[:2]
scale = 800 / width
thumbnail = cv2.resize(marked_image, (800, int(height * scale)))
thumbnail_path = os.path.join(
output_dir, f"female_faces_frame_{frame_number}_thumbnail.jpg"
)
cv2.imwrite(thumbnail_path, thumbnail)
print(f"✅ 已保存縮略圖: {thumbnail_path}")
return {
"original_image": image_path,
"marked_image": output_path,
"thumbnail": thumbnail_path,
"frame_number": frame_number,
"timestamp_seconds": timestamp,
"timestamp_formatted": f"{minutes:02d}:{seconds:02d}",
"female_count": len(female_faces),
"female_faces": [
{
"index": i + 1,
"x": int(x),
"y": int(y),
"width": int(w),
"height": int(h),
"confidence": float(confidence),
"age": int(age) if age else None,
}
for i, (x, y, w, h, confidence, age) in enumerate(female_faces)
],
}
def create_female_faces_report(female_frames_info, output_dir="/tmp/female_faces"):
"""創建女性人臉報告"""
report_path = os.path.join(output_dir, "female_faces_report.md")
with open(report_path, "w", encoding="utf-8") as f:
f.write("# 女性人臉分析報告\n\n")
f.write(f"生成時間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
f.write("## 📊 統計摘要\n\n")
total_females = sum(info["female_count"] for info in female_frames_info)
f.write(f"- **總女性人臉數**: {total_females}\n")
f.write(f"- **分析畫面數**: {len(female_frames_info)}\n")
f.write(
f"- **女性最多畫面**: {max(female_frames_info, key=lambda x: x['female_count'])['female_count']} 個女性\n\n"
)
f.write("## 🖼️ 女性最多的畫面\n\n")
for info in female_frames_info:
if info["female_count"] >= 2: # 只顯示有2個或以上女性的畫面
f.write(
f"### 幀 {info['frame_number']} - {info['timestamp_formatted']}\n\n"
)
f.write(f"- **女性數量**: {info['female_count']}\n")
f.write(
f"- **時間位置**: {info['timestamp_formatted']} ({info['timestamp_seconds']:.1f}秒)\n"
)
f.write(f"- **標記圖像**: `{os.path.basename(info['marked_image'])}`\n")
f.write(f"- **縮略圖**: `{os.path.basename(info['thumbnail'])}`\n\n")
f.write("#### 人臉詳細信息\n\n")
f.write("| 編號 | 位置 (x,y,w,h) | 置信度 | 年齡 |\n")
f.write("|------|----------------|--------|------|\n")
for face in info["female_faces"]:
position = (
f"{face['x']},{face['y']},{face['width']},{face['height']}"
)
confidence = f"{face['confidence']:.1%}"
age = str(face["age"]) if face["age"] else "未知"
f.write(
f"| {face['index']} | {position} | {confidence} | {age} |\n"
)
f.write("\n")
# 添加圖像引用
f.write(f"![女性人臉畫面]({os.path.basename(info['thumbnail'])})\n\n")
f.write(
f"*圖像大小: 原始 {os.path.getsize(info['original_image']):,} bytes, 標記 {os.path.getsize(info['marked_image']):,} bytes*\n\n"
)
f.write("## 📁 生成文件\n\n")
f.write("以下文件已生成:\n\n")
for info in female_frames_info:
if info["female_count"] >= 2:
f.write(
f"- `{os.path.basename(info['marked_image'])}` - 標記女性人臉的完整圖像\n"
)
f.write(
f"- `{os.path.basename(info['thumbnail'])}` - 縮略圖800px寬\n"
)
f.write(f"- `female_faces_report.md` - 本報告文件\n\n")
f.write("## 🔍 分析說明\n\n")
f.write("1. **邊界框顏色**: 粉色 (RGB: 255,105,180) 表示女性人臉\n")
f.write("2. **標籤格式**: `女 [編號] ([年齡]歲) [置信度]`\n")
f.write("3. **置信度**: 人臉檢測的準確度,越高越好\n")
f.write("4. **年齡**: 基於深度學習模型的估計可能有±5歲誤差\n")
f.write("5. **時間位置**: 從視頻開始計算的時間\n\n")
f.write("## 🎬 視頻內容分析\n\n")
# 根據女性分布推測視頻內容
multi_female_frames = [
info for info in female_frames_info if info["female_count"] >= 2
]
if multi_female_frames:
f.write("根據女性人臉分布,視頻可能包含:\n\n")
f.write("1. **社交場合**: 多個女性同時出現,可能是聚會或社交活動\n")
f.write("2. **對話場景**: 女性之間的對話或互動\n")
f.write("3. **群體鏡頭**: 包含多個女性的群體畫面\n")
f.write(
f"4. **女性主導場景**: 在 {len(multi_female_frames)} 個畫面中有2個或以上女性\n"
)
else:
f.write("視頻中女性主要單獨出現,可能包含:\n\n")
f.write("1. **單人鏡頭**: 女性單獨出現的特寫\n")
f.write("2. **分散場景**: 女性分散在不同的畫面中\n")
f.write("3. **配角角色**: 女性可能不是主要角色\n")
print(f"✅ 報告已生成: {report_path}")
return report_path
def main():
print("=" * 70)
print("提取女性最多的畫面")
print("=" * 70)
# 輸出目錄
output_dir = "/tmp/female_faces"
# 找到女性最多的幾個畫面
female_frames = [
19778, # 3個女性最多
17980, # 2個女性
62930, # 2個女性
66526, # 2個女性
70122, # 2個女性
71920, # 2個女性
]
print(f"分析以下幀的女性人臉: {female_frames}")
print()
female_frames_info = []
for frame_number in female_frames:
image_path = (
f"/tmp/face_analysis_results/384b0ff44aaaa1f1_frame_{frame_number:06d}.jpg"
)
if os.path.exists(image_path):
print(f"處理幀 {frame_number}...")
info = draw_female_faces(image_path, frame_number, output_dir)
if info:
female_frames_info.append(info)
print()
else:
print(f"❌ 圖像文件不存在: {image_path}")
if female_frames_info:
# 創建報告
report_path = create_female_faces_report(female_frames_info, output_dir)
print("=" * 70)
print("✅ 提取完成!")
print("=" * 70)
# 顯示摘要
max_females = max(info["female_count"] for info in female_frames_info)
max_frame_info = [
info for info in female_frames_info if info["female_count"] == max_females
][0]
print(f"📊 統計摘要:")
print(f" - 總分析畫面: {len(female_frames_info)}")
print(f" - 女性最多畫面: 幀 {max_frame_info['frame_number']}")
print(f" - 女性數量: {max_females}")
print(f" - 時間位置: {max_frame_info['timestamp_formatted']}")
print()
print(f"📁 生成文件:")
print(f" - 標記圖像: {output_dir}/female_faces_frame_*.jpg")
print(f" - 縮略圖: {output_dir}/female_faces_frame_*_thumbnail.jpg")
print(f" - 分析報告: {report_path}")
print()
print(f"🔍 查看結果:")
print(f" ls -la {output_dir}/")
print(f" open {output_dir}/female_faces_report.md")
else:
print("❌ 未找到任何女性人臉畫面")
if __name__ == "__main__":
main()