效果
QQ录屏20240406131651
语音播放
import pygame
pygame.mixer.init() #初始化
pygame.mixer.music.load(r"7359.wav") #文件位置
pygame.mixer.music.play(1) #播放语音
while pygame.mixer.music.get_busy(): # 在音频播放为完成之前不退出程序pass
完整代码
1.多线程使语音可以播放完,预防卡音。
2.小于35厘米语音提醒并更换距离提醒字体颜色,一般情况下用蓝色字体显示。
3.使用过程中可以把倒数第二行注释掉,不进行窗口的显示,仅判断距离
import cv2
from cvzone.FaceMeshModule import FaceMeshDetector
import pygame
import threading
from PIL import Image, ImageDraw, ImageFont
import numpy as np# 初始化pygame.mixer
pygame.mixer.init()
# 加载音频文件
pygame.mixer.music.load('7359.wav') # 靠的太近啦 #音频文件自行修改
# 设置摄像头
cap = cv2.VideoCapture(0)
detector = FaceMeshDetector(maxFaces=1)
# 定义播放音频的函数
def play_audio():pygame.mixer.music.play(1)while pygame.mixer.music.get_busy():continue
# 开始检测人脸
while True:success, img = cap.read()img, faces = detector.findFaceMesh(img, draw=False)if faces:face = faces[0]pointLeft = face[145]pointRight = face[374]w, _ = detector.findDistance(pointLeft, pointRight)W = 6.3f = 600d = (W * f) / wprint(d)# 设置距离颜色if d < 35:print("过近提醒")# 检查是否正在播放音频if not pygame.mixer.music.get_busy():# 使用线程播放音频,避免阻塞主程序audio_thread = threading.Thread(target=play_audio)audio_thread.start()text_color = (255, 0, 0) # 红色else:text_color = (0, 0, 255) # 蓝色# 将 Depth 文本显示为汉语pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(pil_img)font = ImageFont.truetype("msyh.ttc", 36) # 使用微软雅黑字体,大小为36draw.text((face[10][0] - 95, face[10][1] - 5), f'距离:{int(d)}厘米', font=font, fill=text_color)img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)cv2.imshow("Distance recognition", img) # 窗口名只能是英文cv2.waitKey(1)
UI设计
用pyqt设计了个UI把视频流嵌入
并设计了个进度条用来实时显示距离
输入距离设置 低于xx时自动提醒
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import Qt, QPoint
from esp32_ui import Ui_Form # UI
import ping # qrc生成的py #样式表
import cv2
from cvzone.FaceMeshModule import FaceMeshDetector
import pygame
import threading
from PIL import Image, ImageDraw, ImageFont
import numpy as np
class guWindow(QWidget):def __init__(self):super().__init__()self.gu = Ui_Form()self.gu.setupUi(self)self.gu.lineEdit.returnPressed.connect(self.gumou) # lineEdit回车运行self.video_label = self.gu.label_2# 2 QLabel2self.user_name_qwidget = self.gu.lineEditself.progress_bar = self.gu.progressBar #进度条self.setWindowOpacity(0.90) # 设置窗口透明度self.setWindowFlag(Qt.FramelessWindowHint) # 去除边框self.setAttribute(Qt.WA_TranslucentBackground) # 去除白色背景self.offset = QPoint() # 记录鼠标按下的初始位置def mousePressEvent(self, event):self.offset = event.pos()def mouseMoveEvent(self, event):if event.buttons() == Qt.LeftButton:self.move(self.pos() + event.pos() - self.offset) # 移动窗口位置def gumou(self): # 按钮绑定的函数 功能cap = cv2.VideoCapture(0)detector = FaceMeshDetector(maxFaces=1)pygame.mixer.init()# 加载音频文件pygame.mixer.music.load('7359.wav') # 靠的太近啦def play_audio():pygame.mixer.music.play(1)while pygame.mixer.music.get_busy():continuewhile True:success, img = cap.read()img, faces = detector.findFaceMesh(img, draw=False)if faces:face = faces[0]pointLeft = face[145]pointRight = face[374]w, _ = detector.findDistance(pointLeft, pointRight)W = 6.5f = 600 # 焦距d = (W * f) / wprint(d)# 设置距离颜色if d < 35:print("过近提醒")# 检查是否正在播放音频if not pygame.mixer.music.get_busy():# 使用线程播放音频,避免阻塞主程序audio_thread = threading.Thread(target=play_audio)audio_thread.start()text_color = (255, 0, 0) # 红色else:text_color = (0, 0, 255) # 蓝色# Update the QProgressBar valueself.progress_bar.setValue(int(d))# 将 Depth 文本显示为汉语pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(pil_img)font = ImageFont.truetype("msyh.ttc", 36) # 使用微软雅黑字体,大小为36draw.text((face[10][0] - 95, face[10][1] - 5), f'距离:{int(d)}厘米', font=font, fill=text_color)img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)h, w, c = img.shapebytesPerLine = c * wif c == 3: # 如果颜色通道为3(BGR)q_img = QtGui.QImage(img.data, w, h, bytesPerLine, QtGui.QImage.Format_BGR888)else: # 如果颜色通道为4(BGRA)q_img = QtGui.QImage(img.data, w, h, bytesPerLine, QtGui.QImage.Format_BGRA8888)# Convert QImage to QPixmappixmap = QtGui.QPixmap.fromImage(q_img)# Display QPixmap on QLabelself.video_label.setPixmap(pixmap)self.video_label.setScaledContents(True)self.video_label.update()cv2.waitKey(1)
if __name__ == '__main__':app = QApplication(sys.argv)icon = QtGui.QIcon(':/jay.ico')app.setWindowIcon(icon)# 创建可拖动窗口实例ui = guWindow() # 函数# 显示窗口ui.show()# 启动应用程序事件循环sys.exit(app.exec_())
ui代码
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import Qt, QPoint, pyqtSignal
from esp32_ui import Ui_Form # UI
import ping # qrc生成的py #样式表
import cv2
from cvzone.FaceMeshModule import FaceMeshDetector
import pygame
import threading
from PIL import Image, ImageDraw, ImageFont
import numpy as npclass guWindow(QWidget):close_signal = pyqtSignal()def __init__(self):super().__init__()self.gu = Ui_Form()self.gu.setupUi(self)self.gu.lineEdit.returnPressed.connect(self.gumou) # lineEdit回车运行self.video_label = self.gu.label_2# 2 QLabel2self.user_name_qwidget = self.gu.lineEditself.progress_bar = self.gu.progressBar #进度条self.setWindowOpacity(0.90) # 设置窗口透明度self.setWindowFlag(Qt.FramelessWindowHint) # 去除边框self.setAttribute(Qt.WA_TranslucentBackground) # 去除白色背景self.offset = QPoint() # 记录鼠标按下的初始位置self.close_signal.connect(self.closeEvent)def closeEvent(self, event):# 关闭窗口时发送信号self.stop_capture()def mousePressEvent(self, event):self.offset = event.pos()def mouseMoveEvent(self, event):if event.buttons() == Qt.LeftButton:self.move(self.pos() + event.pos() - self.offset) # 移动窗口位置def gumou(self): # 按钮绑定的函数 功能s = self.user_name_qwidget.text()self.user_name_qwidget.clear()try:distance_threshold = float(s) # 将用户输入的文本转换为浮点数作为距离阈值except ValueError:print("Invalid input. Please enter a valid number.")returncap = cv2.VideoCapture(0)self.detector = FaceMeshDetector(maxFaces=1)pygame.mixer.init()# 加载音频文件pygame.mixer.music.load('7359.wav') # 靠的太近啦self.capture_active = Truedef play_audio():pygame.mixer.music.play(1)while pygame.mixer.music.get_busy():continuewhile self.capture_active:success, img = cap.read()img, faces = self.detector.findFaceMesh(img, draw=False)if faces:face = faces[0]pointLeft = face[145]pointRight = face[374]w, _ = self.detector.findDistance(pointLeft, pointRight)W = 6.5f = 600 # 焦距d = (W * f) / wprint(d)# 设置距离颜色if d < distance_threshold: # 使用用户输入的距离阈值作为判断条件print("过近提醒")# 检查是否正在播放音频if not pygame.mixer.music.get_busy():# 使用线程播放音频,避免阻塞主程序audio_thread = threading.Thread(target=play_audio)audio_thread.start()text_color = (255, 0, 0) # 红色else:text_color = (0, 0, 255) # 蓝色# Update the QProgressBar valueself.progress_bar.setValue(int(d))# 将 Depth 文本显示为汉语pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(pil_img)font = ImageFont.truetype("msyh.ttc", 36) # 使用微软雅黑字体,大小为36draw.text((face[10][0] - 95, face[10][1] - 5), f'距离:{int(d)}厘米', font=font, fill=text_color)img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)h, w, c = img.shapebytesPerLine = c * wif c == 3: # 如果颜色通道为3(BGR)q_img = QtGui.QImage(img.data, w, h, bytesPerLine, QtGui.QImage.Format_BGR888)else: # 如果颜色通道为4(BGRA)q_img = QtGui.QImage(img.data, w, h, bytesPerLine, QtGui.QImage.Format_BGRA8888)# Convert QImage to QPixmappixmap = QtGui.QPixmap.fromImage(q_img)# Display QPixmap on QLabelself.video_label.setPixmap(pixmap)self.video_label.setScaledContents(True)self.video_label.update()cv2.waitKey(1)def stop_capture(self):self.capture_active = Falseif __name__ == '__main__':app = QApplication(sys.argv)icon = QtGui.QIcon(':/jay.ico')app.setWindowIcon(icon)# 创建可拖动窗口实例ui = guWindow() # 函数# 显示窗口ui.show()# 启动应用程序事件循环sys.exit(app.exec_())