这里我没有给 ESP8266 刷入 MicroPython 固件,而是用的Python和Mixly(在Mixly上写的代码,这个是一个可以图形化的软件,也可以进行部分代码编写,当然复杂程序还是用Arduino IDE,这边两者都可实现,以下仅展示用Mixly2.0进行的操作),且是HTTP服务器版本,非MQTT版本。
此篇是在该篇基础上进行了优化可点此处直接跳转,引入了人脸识别(即校验到指定人脸才亮灯)
用了face_recognition人脸识别库,需要先进行安装:
bash
pip install face_recognition
注意如果安装过程中如果有报错类似:
bash
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
You must use Visual Studio to build a python extension on windows. If you
are getting this error it means you have not installed Visual C++. Note
that there are many flavors of Visual Studio, like Visual Studio for C#
development. You need to install Visual Studio for C++.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
可以先安装Visual Studio的C++构建工具
或者直接下载dlib库,然后再pip install face_recognition。
dlib包链接:dlib包链接
以下是代码:
python
import requests
import cv2
import face_recognition
import os
import time
import threading
# ESP8266的IP地址
ESP8266_IP = "192.168.1.12"
BASE_URL = f"http://{ESP8266_IP}"
TEST_URL = f"{BASE_URL}/text/plain"
LED_ON_URL = f"{BASE_URL}/led/on"
LED_OFF_URL = f"{BASE_URL}/led/off"
class FaceRecognitionSystem:
def __init__(self):
"""初始化人脸识别系统"""
self.known_faces_dir = r"D:\PythonProject\known_faces" # 图片存放地址
self.known_face_encodings = []
self.known_face_names = []
self.last_trigger_time = 0
self.led_cooldown = 3 # LED冷却时间(秒)
self.led_is_on = False
# 加载已知人脸
self.load_known_faces()
def load_known_faces(self):
"""加载已知人脸图片"""
if not os.path.exists(self.known_faces_dir):
print(f"已知人脸目录不存在: {self.known_faces_dir}")
return
all_files = os.listdir(self.known_faces_dir)
for filename in all_files:
# 检查文件后缀(兼容大小写)
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
image_path = os.path.join(self.known_faces_dir, filename)
print(f"图片路径: {image_path}")
# 检查文件是否为有效图片
try:
image = face_recognition.load_image_file(image_path)
except Exception as e:
print(f"图片加载失败: {e}")
continue
# 获取人脸编码
face_encodings = face_recognition.face_encodings(image)
if len(face_encodings) > 0:
self.known_face_encodings.append(face_encodings[0])
self.known_face_names.append(os.path.splitext(filename)[0])
print(f"已加载人脸: {filename}")
else:
print(f"未在图片中检测到人脸: {filename}")
else:
print(f"非支持的图片格式: {filename}")
print(f"最终加载人脸数量: {len(self.known_face_encodings)}")
def recognize_faces(self, frame):
"""识别人脸并返回是否匹配已知人脸"""
if not self.known_face_encodings:
return False
# 调整图像大小以加快处理速度
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
# 转换颜色空间 BGR->RGB
rgb_small_frame = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB)
# 检测所有人脸位置
face_locations = face_recognition.face_locations(rgb_small_frame)
if not face_locations:
return False
# 获取所有人脸编码
face_encodings = face_recognition.face_encodings(
rgb_small_frame,
face_locations
)
# 与已知人脸比较
for face_encoding in face_encodings:
matches = face_recognition.compare_faces(
self.known_face_encodings,
face_encoding,
tolerance=0.4
)
# 如果匹配到任意已知人脸
if True in matches:
print("匹配到已知人脸")
return True
else:
print("未匹配到已知人脸")
return False
def control_led(self, should_turn_on):
"""控制LED开关"""
current_time = time.time()
if should_turn_on and not self.led_is_on:
# 检查冷却时间
if current_time - self.last_trigger_time >= self.led_cooldown:
print("检测到已知人脸,正在打开LED...")
response = requests.get(LED_ON_URL, timeout=3)
if response.status_code == 200:
print("LED已打开")
self.led_is_on = True
self.last_trigger_time = current_time
# 设置3秒后关闭的计时器
def turn_off_led():
time.sleep(3)
response = requests.get(LED_OFF_URL, timeout=3)
if response.status_code == 200:
print("✓ LED已关闭")
self.led_is_on = False
timer = threading.Thread(target=turn_off_led)
timer.daemon = True
timer.start()
else:
print(f"无法打开LED: {response.status_code}")
def test_esp8266_connection():
"""测试ESP8266连接"""
print("测试ESP8266连接...")
try:
response = requests.get(f"{BASE_URL}/", timeout=3)
if response.status_code == 200:
print(f"ESP8266连接成功 (IP: {ESP8266_IP})")
return True
except:
print(f"无法连接到ESP8266 (IP: {ESP8266_IP})")
return False
def main():
"""主函数"""
# 测试ESP8266连接
if not test_esp8266_connection():
print("连接测试失败,请检查配置")
return
# 初始化人脸识别系统
face_system = FaceRecognitionSystem()
if not face_system.known_face_encodings:
print("未找到已知人脸,请将人脸图片放入 'known_faces' 文件夹")
return
# 打开摄像头
print("正在打开摄像头...")
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("无法打开摄像头")
return
print("摄像头已打开,退出请按 'q' 键退出程序")
try:
while True:
# 读取摄像头画面
ret, frame = cap.read()
if not ret:
print("无法读取摄像头画面")
break
# 识别人脸
face_detected = face_system.recognize_faces(frame)
# 控制LED
face_system.control_led(face_detected)
# 在画面上显示状态
status_text = "已知人脸" if face_detected else "未知人脸"
color = (0, 255, 0) if face_detected else (0, 0, 255)
cv2.putText(frame, f"status: {status_text}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2)
cv2.putText(frame, "LED: ON" if face_system.led_is_on else "LED: OFF",
(10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1,
(0, 255, 255) if face_system.led_is_on else (128, 128, 128), 2)
cv2.putText(frame, "Press 'q' to quit", (10, frame.shape[0] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
# 显示画面
cv2.imshow('FaceRecognition', frame)
# 按'q'退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 控制处理频率,避免过于频繁
time.sleep(0.1)
except Exception as e:
print(f"\n程序出错: {e}")
finally:
# 释放资源
cap.release()
cv2.destroyAllWindows()
# 确保LED关闭
try:
if face_system.led_is_on:
requests.get(LED_OFF_URL, timeout=2)
print("程序退出,LED已关闭")
except:
pass
print("程序已结束")
if __name__ == "__main__":
main()
仍有可优化地方:比如将图片上传到云,从云获取,然后上传时候就进行图片人脸编码,摄像头识别到时可以直接获取。
以上是所有内容,感谢观看。