-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
269 lines (226 loc) · 9.25 KB
/
main.py
File metadata and controls
269 lines (226 loc) · 9.25 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#File: main.py
#Description: file nay nhan dien khuon mat theo du lieu da train tu file classifier.xml
import cv2
import time
import numpy as np
from gpiozero import LED
# Initialize GPIO
output = LED(14)
def detect_face_region(image):
"""
Detect faces in the image and return their coordinates.
"""
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
faces = face_cascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
return faces
def remove_background(image, face_regions):
"""
Remove the background outside the detected face regions.
"""
mask = np.zeros(image.shape[:2], dtype=np.uint8)
for (x, y, w, h) in face_regions:
mask[y:y + h, x:x + w] = 255
# Refine the mask to ensure only the face region remains
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
mask = cv2.dilate(mask, kernel, iterations=2)
mask = cv2.erode(mask, kernel, iterations=2)
# Apply Gaussian blur to smooth transitions
mask = cv2.GaussianBlur(mask, (21, 21), 0)
# Apply the mask to the image
result = cv2.bitwise_and(image, image, mask=mask)
return result
def filter_regions_by_shape(mask, points, max_deviation=5, max_size=5000, min_size=10):
"""
Lọc các mảng lớn hoặc quá lệch so với đường xu hướng.
"""
# Phân tích các thành phần kết nối (connected components)
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)
# Tạo mặt nạ mới để giữ lại các vùng phù hợp
refined_mask = np.zeros_like(mask)
for i in range(1, num_labels): # Bỏ qua background (label 0)
area = stats[i, cv2.CC_STAT_AREA]
x, y, w, h = stats[i, cv2.CC_STAT_LEFT], stats[i, cv2.CC_STAT_TOP], stats[i, cv2.CC_STAT_WIDTH], stats[
i, cv2.CC_STAT_HEIGHT]
# Loại bỏ các mảng quá lớn hoặc quá nhỏ
if area < min_size or area > max_size:
continue
# Lấy tất cả các điểm trong vùng này
component_mask = (labels == i).astype(np.uint8)
component_points = cv2.findNonZero(component_mask)
# Tính đường xu hướng (linear regression)
m, b = fit_trend_line(component_points)
# Kiểm tra độ lệch của từng điểm trong vùng
avg_deviation, _ = calculate_average_deviation(component_points, m, b)
if avg_deviation > max_deviation:
continue # Bỏ qua nếu độ lệch quá lớn
# Giữ lại vùng này trong mặt nạ mới
refined_mask = cv2.bitwise_or(refined_mask, component_mask)
return refined_mask
def keep_red_on_face(image, face_regions, red_threshold=240, color_diff=40, brightness_threshold=200):
"""
Giữ lại các điểm đỏ trên khuôn mặt và làm đen các vùng khác.
"""
red_channel = image[:, :, 2]
green_channel = image[:, :, 1]
blue_channel = image[:, :, 0]
# Tạo mặt nạ điểm đỏ nghiêm ngặt
red_mask = (
(red_channel > red_threshold) &
(red_channel > green_channel + color_diff) &
(red_channel > blue_channel + color_diff)
).astype(np.uint8)
# Loại bỏ các điểm có độ sáng quá cao
brightness = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
brightness_mask = (brightness < brightness_threshold).astype(np.uint8)
# Kết hợp mặt nạ đỏ với mặt nạ độ sáng
red_mask = cv2.bitwise_and(red_mask, brightness_mask)
# Tạo mặt nạ khuôn mặt
face_mask = np.zeros_like(red_mask)
for (x, y, w, h) in face_regions:
face_mask[y:y+h, x:x+w] = 1 # Đánh dấu vùng khuôn mặt
# Kết hợp để giữ điểm đỏ trong vùng khuôn mặt
combined_mask = cv2.bitwise_and(red_mask, face_mask)
# Lấy tọa độ các điểm đỏ
points = cv2.findNonZero(combined_mask)
return combined_mask, points
def fit_trend_line(points):
"""
Calculate the trend line from points (y = mx + b).
"""
points = points.squeeze()
if points.ndim != 2 or points.shape[1] != 2:
raise ValueError("Points should be a 2D array with shape (N, 2).")
x_coords = points[:, 0]
y_coords = points[:, 1]
A = np.vstack([x_coords, np.ones(len(x_coords))]).T
m, b = np.linalg.lstsq(A, y_coords, rcond=None)[0]
return m, b
def calculate_average_deviation(points, m, b):
"""
Calculate average deviation and variance of points from the trend line.
"""
if m == 0 and b == 0:
return 0, 0
points = points.squeeze()
distances = []
for x, y in points:
distance = abs(m * x - y + b) / np.sqrt(m ** 2 + 1)
distances.append(distance)
return np.mean(distances), np.var(distances)
def process_laser_image(image):
"""
Process the laser image to identify 3D or 2D surfaces.
"""
# Detect face
face_regions = detect_face_region(image)
if len(face_regions) == 0:
print("No face detected!")
output.off() # Turn off Pin
return None, None
# Remove background outside face regions
image_no_bg = remove_background(image, face_regions)
# Filter red points in the face region
red_mask, points = keep_red_on_face(image_no_bg, face_regions)
if points is None:
print("No red points detected on the face!")
return None, None
try:
# Calculate trend line and deviation
m, b = fit_trend_line(points)
avg_deviation, variance = calculate_average_deviation(points, m, b)
except ValueError as e:
print("SKIP CONFLICT")
print()
print()
print()
print()
print()
m, b = 0, 0
avg_deviation, variance = calculate_average_deviation(points, 0, 0)
# # Display results
#result_image = cv2.bitwise_and(image, image, mask=red_mask)
# cv2.imshow("Original Image", image)
# cv2.imshow("Red Points on Face", result_image)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
return avg_deviation, variance
def draw_boundary(img, classfier, scaleFactor, minNeighbors, color, text, clf):
"""
ham set up toa do cho duong bao khuon mat
:param img: anh ban dau
:param classfier: doi tuong phan loai
:param scaleFactor: dieu chinh scale (float)
:param minNeighbors: so luong lang gieng
:param color: mau RGB
:param text: van ban hien thi ten nguoi
:param clf: bien tu cv2.face.LBPHFaceRecognizer_create()
:return: coords (toa do khuon mat)
"""
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
features = classfier.detectMultiScale(gray_img, scaleFactor, minNeighbors)
coords = []
for (x,y,w,h) in features:
cv2.rectangle(img, (x,y), (x+w, y+h), color, 2)
id, confidence =clf.predict(gray_img[y:y+h, x:x+w])
print("Id khuon mat: ",id)
if confidence > 80:
cv2.putText(img, "Stranger", (x,y - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 1, cv2.LINE_AA )
elif id == 2:
cv2.putText(img, "Duy", (x,y - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 1, cv2.LINE_AA )
elif id == 3:
cv2.putText(img, "DVH", (x, y - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 1, cv2.LINE_AA)
coords = [x,y,w,h]
return coords
def recognize(img, clf, faceCascade):
"""
ham render ra o vuong khuon mat
:param img: anh khuon mat tu data
:param clf: cv2.face_LBPHFaceRecognizer - phan loai cua openCV
:param faceCascade: cv2.CascadeClassifier - phan loai cua haar cascade
:return:
"""
color = {"blue": (255, 0, 0), "red": (0, 0, 255), "green": (0, 255, 0), "white":(255,255,255)}
coords = draw_boundary(img, faceCascade, 1.1, 10, color["white"], "Face", clf)
return img
def main():
"""
ham main
:return:
"""
faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
eyeCascade = cv2.CascadeClassifier("haarcascade_eye.xml")
noseCascade = cv2.CascadeClassifier("Nariz.xml")
mouthCascade = cv2.CascadeClassifier("Mouth.xml")
clf = cv2.face.LBPHFaceRecognizer_create()
clf.read("classifier.xml")
video_capture = cv2.VideoCapture(0)
img_id = 0
if not video_capture.isOpened():
print("Không thể mở camera")
else:
print("Camera đã được mở thành công")
while True:
_, img = video_capture.read()
img = recognize(img, clf, faceCascade)
avg_deviation, variance = process_laser_image(img)
print(avg_deviation)
if avg_deviation is None:
print("Laser line not detected!")
else:
print(f"Average Deviation: {avg_deviation}, Variance: {variance}")
if avg_deviation >= 2.0 and variance >= 1:
output.on() # Turn on Pin
print("3D face detected (Real Person)")
else:
print("2D face detected (Photo)")
output.off() # Turn off Pin
time.sleep(0.05)
cv2.imshow("face detection", img)
img_id += 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
output.off() # Turn off Pin
cv2.destroyAllWindows()
if __name__ == "__main__":
main()