当前位置:   article > 正文

Arduino开发 esp32cam+opencv人脸识别距离+语音提醒_esp32 arduino摄像头代码

esp32 arduino摄像头代码

效果

低于20厘米语音提醒字体变红

QQ录屏20240406131651

Arduino代码

可直接复制使用(修改自己的WIFI)

  1. #include <esp32cam.h>
  2. #include <WebServer.h>
  3. #include <WiFi.h>
  4. // 设置要连接的WiFi名称和密码
  5. const char* WIFI_SSID = "gumou";
  6. const char* WIFI_PASS = "gu3456789";
  7. WebServer server(80);
  8. // 设置不同分辨率的静态变量
  9. static auto loRes = esp32cam::Resolution::find(320, 240);
  10. static auto hiRes = esp32cam::Resolution::find(1280, 1024);
  11. // 处理BMP图像请求
  12. void handleBmp() {
  13. if (!esp32cam::Camera.changeResolution(loRes)) {
  14. Serial.println("SET-LO-RES FAIL");
  15. }
  16. auto frame = esp32cam::capture();
  17. if (frame == nullptr) {
  18. Serial.println("CAPTURE FAIL");
  19. server.send(503, "", "");
  20. return;
  21. }
  22. if (!frame->toBmp()) {
  23. Serial.println("CONVERT FAIL");
  24. server.send(503, "", "");
  25. return;
  26. }
  27. server.setContentLength(frame->size());
  28. server.send(200, "image/bmp");
  29. WiFiClient client = server.client();
  30. frame->writeTo(client);
  31. }
  32. // 服务JPG图像请求
  33. void serveJpg() {
  34. auto frame = esp32cam::capture();
  35. if (frame == nullptr) {
  36. Serial.println("CAPTURE FAIL");
  37. server.send(503, "", "");
  38. return;
  39. }
  40. server.setContentLength(frame->size());
  41. server.send(200, "image/jpeg");
  42. WiFiClient client = server.client();
  43. frame->writeTo(client);
  44. }
  45. // 处理低分辨率JPG请求
  46. void handleJpgLo() {
  47. if (!esp32cam::Camera.changeResolution(loRes)) {
  48. Serial.println("SET-LO-RES FAIL");
  49. }
  50. serveJpg();
  51. }
  52. // 处理高分辨率JPG请求
  53. void handleJpgHi() {
  54. if (!esp32cam::Camera.changeResolution(hiRes)) {
  55. Serial.println("SET-HI-RES FAIL");
  56. }
  57. serveJpg();
  58. }
  59. // 处理JPG请求
  60. void handleJpg() {
  61. server.sendHeader("Location", "/cam-hi.jpg");
  62. server.send(302, "", "");
  63. }
  64. // 处理MJPEG流请求
  65. void handleMjpeg() {
  66. if (!esp32cam::Camera.changeResolution(hiRes)) {
  67. Serial.println("SET-HI-RES FAIL");
  68. }
  69. Serial.println("STREAM BEGIN");
  70. WiFiClient client = server.client();
  71. auto startTime = millis();
  72. int res = esp32cam::Camera.streamMjpeg(client);
  73. if (res <= 0) {
  74. Serial.printf("STREAM ERROR %d\n", res);
  75. return;
  76. }
  77. auto duration = millis() - startTime;
  78. Serial.printf("STREAM END %dfrm %0.2ffps\n", res, 1000.0 * res / duration);
  79. }
  80. void setup() {
  81. Serial.begin(115200);
  82. Serial.println();
  83. // 初始化摄像头
  84. {
  85. using namespace esp32cam;
  86. Config cfg;
  87. cfg.setPins(pins::AiThinker);
  88. cfg.setResolution(hiRes);
  89. cfg.setBufferCount(2);
  90. cfg.setJpeg(80);
  91. bool ok = Camera.begin(cfg);
  92. Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
  93. }
  94. // 连接WiFi
  95. WiFi.persistent(false);
  96. WiFi.mode(WIFI_STA);
  97. WiFi.begin(WIFI_SSID, WIFI_PASS);
  98. while (WiFi.status() != WL_CONNECTED) {
  99. delay(500);
  100. }
  101. // 打印服务器地址和端口
  102. Serial.print("http://");
  103. Serial.println(WiFi.localIP());
  104. Serial.println(" /cam.bmp");
  105. Serial.println(" /cam-lo.jpg");
  106. Serial.println(" /cam-hi.jpg");
  107. Serial.println(" /cam.mjpeg");
  108. // 定义服务器路由
  109. server.on("/cam.bmp", handleBmp);
  110. server.on("/cam-lo.jpg", handleJpgLo);
  111. server.on("/cam-hi.jpg", handleJpgHi);
  112. server.on("/cam.jpg", handleJpg);
  113. server.on("/cam.mjpeg", handleMjpeg);
  114. // 启动服务器
  115. server.begin();
  116. }
  117. void loop() {
  118. // 处理客户端请求
  119. server.handleClient();
  120. }

查看Esp32的IP地址

录入后,在串口监视器处查看IP(自动会输出)

录入前要把波特率调整115200

python端计算代码

可更改 1.IP地址 2.提醒语音 3.提醒距离 4.可删除倒数第二行 不显示画面 只测量距离

  1. import urllib
  2. import cv2
  3. import numpy as np
  4. from cvzone.FaceMeshModule import FaceMeshDetector
  5. import pygame
  6. import threading
  7. from PIL import Image, ImageDraw, ImageFont
  8. # 初始化pygame.mixer
  9. pygame.mixer.init()
  10. # 加载音频文件
  11. pygame.mixer.music.load('7359.wav') # 靠的太近啦音频
  12. detector = FaceMeshDetector(maxFaces=1)
  13. url = 'http://192.168.85.168/cam-hi.jpg' # 改成自己的IP地址+/cam-hi.jpg
  14. # 定义播放音频的函数
  15. def play_audio():
  16. pygame.mixer.music.play(1)
  17. while pygame.mixer.music.get_busy():
  18. continue
  19. # 函数:从ESP32CAM获取图像
  20. def get_esp32cam_image(url):
  21. img_resp = urllib.request.urlopen(url)
  22. img_np = np.array(bytearray(img_resp.read()), dtype=np.uint8)
  23. img = cv2.imdecode(img_np, -1)
  24. return img
  25. # 开始检测人脸距离
  26. while True:
  27. # 从ESP32CAM获取图像
  28. img = get_esp32cam_image(url)
  29. # 检测人脸
  30. img, faces = detector.findFaceMesh(img, draw=False)
  31. if faces:
  32. face = faces[0]
  33. point_left = face[145]
  34. point_right = face[374]
  35. w, _ = detector.findDistance(point_left, point_right)
  36. W = 6.3
  37. f = 600
  38. d = (W * f) / w
  39. print(d)
  40. # 设置距离颜色
  41. if d < 20:
  42. print("过近提醒")
  43. # 检查是否正在播放音频
  44. if not pygame.mixer.music.get_busy():
  45. # 使用线程播放音频,避免阻塞主程序
  46. audio_thread = threading.Thread(target=play_audio)
  47. audio_thread.start()
  48. text_color = (255, 0, 0) # 红色
  49. else:
  50. text_color = (0, 0, 255) # 蓝色
  51. # 将Depth文本显示为汉语
  52. pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
  53. draw = ImageDraw.Draw(pil_img)
  54. font = ImageFont.truetype("msyh.ttc", 36) # 使用微软雅黑字体,大小为36
  55. draw.text((face[10][0] - 95, face[10][1] - 5), f'距离:{int(d)}厘米', font=font, fill=text_color)
  56. img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
  57. cv2.imshow("Distance recognition", img) #这行注释掉后可以不显示摄像头窗口只输出距离
  58. if cv2.waitKey(1) == ord('q'):
  59. break
  60. cv2.destroyAllWindows()

手机端查看  IP地址同上

图片

http://192.168.85.168/cam-hi.jpg

视频

http://192.168.85.168/cam.mjpeg

UI设计

设计ui之后画面较小 若摄像头分辨率较低建议使用上面的代码

  1. import sys
  2. from PyQt5 import QtGui
  3. from PyQt5.QtWidgets import QApplication, QWidget
  4. from PyQt5.QtCore import Qt, QPoint, pyqtSignal
  5. from esp32_ui import Ui_Form # UI
  6. import cv2
  7. from cvzone.FaceMeshModule import FaceMeshDetector
  8. import pygame
  9. import threading
  10. from PIL import Image, ImageDraw, ImageFont
  11. import numpy as np
  12. import urllib.request
  13. import ping
  14. class guWindow(QWidget):
  15. close_signal = pyqtSignal()
  16. def __init__(self):
  17. super().__init__()
  18. self.gu = Ui_Form()
  19. self.gu.setupUi(self)
  20. self.gu.lineEdit.returnPressed.connect(self.gumou) # lineEdit回车运行
  21. self.video_label = self.gu.label_2# 2 QLabel2
  22. self.user_name_qwidget = self.gu.lineEdit
  23. self.progress_bar = self.gu.progressBar #进度条
  24. self.setWindowOpacity(0.90) # 设置窗口透明度
  25. self.setWindowFlag(Qt.FramelessWindowHint) # 去除边框
  26. self.setAttribute(Qt.WA_TranslucentBackground) # 去除白色背景
  27. self.offset = QPoint() # 记录鼠标按下的初始位置
  28. self.close_signal.connect(self.closeEvent)
  29. def closeEvent(self, event):
  30. # 关闭窗口时发送信号
  31. self.stop_capture()
  32. def mousePressEvent(self, event):
  33. self.offset = event.pos()
  34. def mouseMoveEvent(self, event):
  35. if event.buttons() == Qt.LeftButton:
  36. self.move(self.pos() + event.pos() - self.offset) # 移动窗口位置
  37. def gumou(self): # 按钮绑定的函数 功能
  38. s = self.user_name_qwidget.text()
  39. self.user_name_qwidget.clear()
  40. try:
  41. distance_threshold = float(s) # 将用户输入的文本转换为浮点数作为距离阈值
  42. except ValueError:
  43. print("Invalid input. Please enter a valid number.")
  44. return
  45. pygame.mixer.init()
  46. # 加载音频文件
  47. pygame.mixer.music.load('7359.wav') # 靠的太近啦
  48. self.capture_active = True
  49. def play_audio():
  50. pygame.mixer.music.play(1)
  51. while pygame.mixer.music.get_busy():
  52. continue
  53. while self.capture_active:
  54. img = get_esp32cam_image('http://192.168.85.168/cam-hi.jpg') # Get image from ESP32CAM
  55. if img is not None:
  56. self.detect_and_display(img, distance_threshold, play_audio)
  57. def detect_and_display(self, img, distance_threshold, play_audio):
  58. self.detector = FaceMeshDetector(maxFaces=1)
  59. img, faces = self.detector.findFaceMesh(img, draw=False)
  60. if faces:
  61. face = faces[0]
  62. pointLeft = face[145]
  63. pointRight = face[374]
  64. w, _ = self.detector.findDistance(pointLeft, pointRight)
  65. W = 6.5
  66. f = 600 # 焦距
  67. d = (W * f) / w
  68. print(d)
  69. # 设置距离颜色
  70. if d < distance_threshold: # 使用用户输入的距离阈值作为判断条件
  71. print("过近提醒")
  72. # 检查是否正在播放音频
  73. if not pygame.mixer.music.get_busy():
  74. # 使用线程播放音频,避免阻塞主程序
  75. audio_thread = threading.Thread(target=play_audio)
  76. audio_thread.start()
  77. text_color = (255, 0, 0) # 红色
  78. else:
  79. text_color = (0, 0, 255) # 蓝色
  80. # Update the QProgressBar value
  81. self.progress_bar.setValue(int(d))
  82. # 将 Depth 文本显示为汉语
  83. pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
  84. draw = ImageDraw.Draw(pil_img)
  85. font = ImageFont.truetype("msyh.ttc", 36) # 使用微软雅黑字体,大小为36
  86. draw.text((face[10][0] - 95, face[10][1] - 5), f'距离:{int(d)}厘米', font=font, fill=text_color)
  87. img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
  88. h, w, c = img.shape
  89. bytesPerLine = c * w
  90. if c == 3: # 如果颜色通道为3(BGR)
  91. q_img = QtGui.QImage(img.data, w, h, bytesPerLine, QtGui.QImage.Format_BGR888)
  92. else: # 如果颜色通道为4(BGRA)
  93. q_img = QtGui.QImage(img.data, w, h, bytesPerLine, QtGui.QImage.Format_BGRA8888)
  94. # Convert QImage to QPixmap
  95. pixmap = QtGui.QPixmap.fromImage(q_img)
  96. # Display QPixmap on QLabel
  97. self.video_label.setPixmap(pixmap)
  98. self.video_label.setScaledContents(True)
  99. self.video_label.update()
  100. cv2.waitKey(1)
  101. def stop_capture(self):
  102. self.capture_active = False
  103. def get_esp32cam_image(url):
  104. img_resp = urllib.request.urlopen(url)
  105. img_np = np.array(bytearray(img_resp.read()), dtype=np.uint8)
  106. img = cv2.imdecode(img_np, -1)
  107. return img
  108. if __name__ == '__main__':
  109. app = QApplication(sys.argv)
  110. icon = QtGui.QIcon(':/jay.ico')
  111. app.setWindowIcon(icon)
  112. # 创建可拖动窗口实例
  113. ui = guWindow() # 函数
  114. # 显示窗口
  115. ui.show()
  116. # 启动应用程序事件循环
  117. sys.exit(app.exec_())

项目踩坑

1.驱动ESP32-CAM 这里下载zip自己导入

2.配置开发板 

Arduino中文社区

从这里下载会自动安装指定位置

不要在图中位置配置,速度太慢!!

3.python识别面部距离,需要电脑端和esp32-cam同时连接一个WIFI

由于esp32-cam连WIFI能力较差

(若手机开热点供双方连接,建议esp32-cam先连接后再让电脑连)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/406561
推荐阅读
相关标签
  

闽ICP备14008679号