-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfive_elements_artistic.py
More file actions
128 lines (106 loc) · 4.6 KB
/
five_elements_artistic.py
File metadata and controls
128 lines (106 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import cv2
import mediapipe as mp
import numpy as np
import math
import time
# 初始化 mediapipe
mp_face_mesh = mp.solutions.face_mesh
# 五行颜色风格(BGR)
colors = {
"Gold": (21, 200, 236), # 金
"Wood": (106, 189, 18), # 木
"Water": (174, 163, 89), # 水
"Fire": (34, 56, 186), # 火
"Soil": (71, 87, 132), # 土
"Balanced": (255, 255, 255)
}
# 五行对应说明文字
element_text = {
"Gold": "Gold (strong and defined)",
"Wood": "Wood (long and upward)",
"Water": "Water (round and soft)",
"Fire": "Fire (sharp and vivid)",
"Soil": "Soil (stable and square)",
"Balanced": "Balanced (harmony)"
}
# 判断脸型
def get_face_shape(landmarks, w, h):
jaw_width = np.linalg.norm(np.array([landmarks[234].x * w, landmarks[234].y * h]) -
np.array([landmarks[454].x * w, landmarks[454].y * h]))
face_height = np.linalg.norm(np.array([landmarks[10].x * w, landmarks[10].y * h]) -
np.array([landmarks[152].x * w, landmarks[152].y * h]))
ratio = jaw_width / face_height
if ratio < 0.65:
return "Wood"
elif ratio < 0.75:
return "Fire"
elif ratio < 0.85:
return "Water"
elif ratio < 0.95:
return "Gold"
else:
return "Soil"
# 打开摄像头
cap = cv2.VideoCapture(0)
# 设置摄像头分辨率(可根据实际屏幕比例调整)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
# 创建窗口并设置为全屏
cv2.namedWindow("Five Elements - Artistic Mode", cv2.WINDOW_NORMAL)
cv2.setWindowProperty("Five Elements - Artistic Mode", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
start_time = time.time()
with mp_face_mesh.FaceMesh(max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5) as face_mesh:
while True:
ret, frame = cap.read()
if not ret:
break
frame = cv2.flip(frame, 1)
h, w, _ = frame.shape
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = face_mesh.process(rgb_frame)
# --- 背景马赛克 ---
small = cv2.resize(frame, (w // 30, h // 30))
mosaic = cv2.resize(small, (w, h), interpolation=cv2.INTER_NEAREST)
mosaic = cv2.addWeighted(frame, 0.6, mosaic, 0.4, 0) # 弱化60%
mask = np.zeros((h, w), np.uint8)
overlay = np.zeros_like(frame, dtype=np.uint8)
face_type = "Balanced"
adjusted_color = (255, 255, 255)
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
points = np.array([[int(lm.x * w), int(lm.y * h)] for lm in face_landmarks.landmark])
hull = cv2.convexHull(points)
cv2.fillConvexPoly(mask, hull, 255)
# 获取五行类型
face_type = get_face_shape(face_landmarks.landmark, w, h)
base_color = np.array(colors[face_type], dtype=np.float32)
# 光感柔和波动
t = time.time() - start_time
pulse = 0.1 + 0.02 * math.sin(t * 2)
adjusted_color = tuple((base_color * (0.85 + pulse)).clip(0, 255).astype(int).tolist())
# 绘制点和线
FACEMESH_LINES = list(mp_face_mesh.FACEMESH_CONTOURS) + list(mp_face_mesh.FACEMESH_FACE_OVAL)
for lm in face_landmarks.landmark:
x, y = int(lm.x * w), int(lm.y * h)
cv2.circle(overlay, (x, y), 1, adjusted_color, -1)
for conn in FACEMESH_LINES:
i1, i2 = conn
x1, y1 = int(face_landmarks.landmark[i1].x * w), int(face_landmarks.landmark[i1].y * h)
x2, y2 = int(face_landmarks.landmark[i2].x * w), int(face_landmarks.landmark[i2].y * h)
cv2.line(overlay, (x1, y1), (x2, y2), adjusted_color, 1)
# --- 合成层 ---
face_clear = cv2.bitwise_and(frame, frame, mask=mask)
background = cv2.bitwise_and(mosaic, mosaic, mask=cv2.bitwise_not(mask))
combined = cv2.add(face_clear, background)
combined = cv2.addWeighted(combined, 1.0, overlay, 0.3, 0)
# --- 在最上层绘制文字 ---
text = element_text[face_type]
text_color = tuple(int(c) for c in adjusted_color)
cv2.putText(combined, text, (60, 100),
cv2.FONT_HERSHEY_SIMPLEX, 1.2, text_color, 3, cv2.LINE_AA)
cv2.imshow("Five Elements - Artistic Mode", combined)
# 按下 q 退出
if cv2.waitKey(5) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()