Загрузка...

Python Софт для отслеживания лица + жестов рук

Тема в разделе Ваши работы создана пользователем rasez 21 июн 2025. 163 просмотра

Опрос

аценку

Другие смогут видеть, как Вы проголосовали.
  1. имба

    2
    66,7%
  2. какаха

    0
    0%
  3. 50/50

    0
    0%
  4. сойдет

    1
    33,3%
  1. rasez
    rasez Автор темы 21 июн 2025 Стим аккаунты тут - lolz.live/threads/7680775 :da: 1481 29 апр 2025
    Опять же сидел ерунду учил :da:
    На своем любимом Pyqt5 и mediapipe+cv2 написал какую то супер крутую программу для отслежки
    лица детального жестов и вроде как емоций
    :shreklol:

    Ниче не понял по документации использования
    гпт фиксил все ошибки а их было ну примерноо миллион :kakashka: :kakashka:
    Оч плохо работает но также высчитывает +- угол поворота и тп вашего лица ну головы епта
    :colobok_cool:
    [IMG]
    Как вы можете заметить очень даже качественно выполнено все было :fap:
    Python
    import sys
    import cv2
    import numpy as np
    import mediapipe as mp
    import time
    import winsound
    from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
    from PyQt5.QtGui import QImage, QPixmap, QFont
    from PyQt5.QtWidgets import (
    QApplication, QWidget, QLabel, QPushButton, QCheckBox,
    QVBoxLayout, QHBoxLayout, QGroupBox, QSpacerItem, QSizePolicy,
    QMessageBox, QFileDialog
    )


    class VideoThread(QThread):
    change_pixmap_signal = pyqtSignal(QImage)
    update_fps_signal = pyqtSignal(float)
    gesture_signal = pyqtSignal(str)
    stats_signal = pyqtSignal(str)
    emotion_signal = pyqtSignal(str)

    def __init__(self, camera_id=0):
    super().__init__()
    self.cap = cv2.VideoCapture(camera_id)
    self.camera_id = camera_id
    self._run_flag = True
    self.rotation_angle = 0

    self.mp_face_mesh = mp.solutions.face_mesh
    self.mp_hands = mp.solutions.hands
    self.mp_drawing = mp.solutions.drawing_utils
    self.face_mesh = self.mp_face_mesh.FaceMesh(
    max_num_faces=1,
    refine_landmarks=True,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5)
    self.hands = self.mp_hands.Hands(
    max_num_hands=2,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5)

    self.track_face = False
    self.track_detailed_face = False
    self.track_hands = False
    self.show_fps = False
    self.sound_alerts = False
    self.dark_theme = True

    self.prev_time = 0

    def run(self):
    while self._run_flag:
    ret, frame = self.cap.read()
    if not ret:
    continue

    frame = cv2.flip(frame, 1)
    frame = self.rotate_frame(frame, self.rotation_angle)
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

    results_face = None
    results_hands = None

    if self.track_face or self.track_detailed_face:
    results_face = self.face_mesh.process(rgb_frame)

    if self.track_hands:
    results_hands = self.hands.process(rgb_frame)

    h, w, _ = frame.shape
    gesture_text = ""
    emotion_text = ""
    faces_count = 0
    hands_count = 0
    hands_raised = 0
    yaw, pitch, roll = 0, 0, 0

    if results_face and results_face.multi_face_landmarks:
    faces_count = len(results_face.multi_face_landmarks)
    for face_landmarks in results_face.multi_face_landmarks:

    if self.track_face:
    x_coords = [int(lm.x * w) for lm in face_landmarks.landmark]
    y_coords = [int(lm.y * h) for lm in face_landmarks.landmark]
    x_min, x_max = min(x_coords), max(x_coords)
    y_min, y_max = min(y_coords), max(y_coords)
    padding_x = int((x_max - x_min) * 0.1)
    padding_y = int((y_max - y_min) * 0.15)
    x_min = max(0, x_min - padding_x)
    x_max = min(w, x_max + padding_x)
    y_min = max(0, y_min - padding_y)
    y_max = min(h, y_max + padding_y)
    cv2.rectangle(frame, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)

    if self.track_detailed_face:
    self.mp_drawing.draw_landmarks(
    frame, face_landmarks,
    self.mp_face_mesh.FACEMESH_TESSELATION,
    landmark_drawing_spec=None,
    connection_drawing_spec=mp.solutions.drawing_styles.get_default_face_mesh_tesselation_style())

    emotion_text = self.detect_emotion(face_landmarks, frame)

    yaw, pitch, roll = self.estimate_head_pose(face_landmarks, w, h)

    mouth_open = self.is_mouth_open(face_landmarks, h)
    if mouth_open:
    mouth_points = [face_landmarks.landmark[i] for i in range(78, 88)]
    pts = np.array([(int(p.x * w), int(p.y * h)) for p in mouth_points])
    cv2.polylines(frame, [pts], True, (0, 0, 255), 2)

    if results_hands and results_hands.multi_hand_landmarks:
    hands_count = len(results_hands.multi_hand_landmarks)
    for hand_landmarks in results_hands.multi_hand_landmarks:
    self.mp_drawing.draw_landmarks(frame, hand_landmarks, self.mp_hands.HAND_CONNECTIONS)
    wrist_y = hand_landmarks.landmark[self.mp_hands.HandLandmark.WRIST].y * h
    middle_finger_tip_y = hand_landmarks.landmark[self.mp_hands.HandLandmark.MIDDLE_FINGER_TIP].y * h
    if middle_finger_tip_y < wrist_y:
    hands_raised += 1

    if hands_raised == 1:
    gesture_text = "Рука поднята "
    if self.sound_alerts:
    winsound.Beep(800, 150)
    elif hands_raised == 2:
    gesture_text = "Две руки подняты "
    if self.sound_alerts:
    winsound.Beep(1000, 150)
    else:
    gesture_text = ""

    if self.show_fps:
    curr_time = time.time()
    fps = 1.0 / (curr_time - self.prev_time) if self.prev_time else 0
    self.prev_time = curr_time
    self.update_fps_signal.emit(fps)
    cv2.putText(frame, f'FPS: {int(fps)}', (10, 30),
    cv2.FONT_HERSHEY_SIMPLEX, 0.8, (50, 150, 50), 2)
    else:
    self.update_fps_signal.emit(0)

    stats_text = f"Лицо: {faces_count} | Руки: {hands_count} | Эмоция: {emotion_text} | Жесты: {gesture_text}"
    self.stats_signal.emit(stats_text)

    if emotion_text:
    cv2.putText(frame, f"Emotion: {emotion_text}", (10, 60),
    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (80, 200, 80), 2)

    cv2.putText(frame, f"Incline (yaw,pitch,roll): {int(yaw)},{int(pitch)},{int(roll)}", (10, 90),
    cv2.FONT_HERSHEY_SIMPLEX, 0.6, (100, 255, 100), 1)

    h, w, ch = frame.shape
    bytes_per_line = ch * w
    qt_image = QImage(frame.data, w, h, bytes_per_line, QImage.Format_BGR888)
    self.change_pixmap_signal.emit(qt_image)

    self.gesture_signal.emit(gesture_text)
    self.emotion_signal.emit(emotion_text)

    self.cap.release()

    def detect_emotion(self, face_landmarks, frame):
    h, w, _ = frame.shape

    left_mouth = face_landmarks.landmark[61]
    right_mouth = face_landmarks.landmark[291]
    top_lip = face_landmarks.landmark[13]
    bottom_lip = face_landmarks.landmark[14]
    left_eyebrow = face_landmarks.landmark[70]
    right_eyebrow = face_landmarks.landmark[300]
    left_eye = face_landmarks.landmark[159]
    right_eye = face_landmarks.landmark[386]

    mouth_width = abs(right_mouth.x - left_mouth.x)
    mouth_height = abs(top_lip.y - bottom_lip.y)
    eyebrow_height = abs(left_eyebrow.y - left_eye.y) + abs(right_eyebrow.y - right_eye.y)

    if mouth_height / mouth_width > 0.3:
    return "Smiling"
    if eyebrow_height < 0.03:
    return "Default"
    return ""

    def is_mouth_open(self, face_landmarks, h):
    top_lip_y = face_landmarks.landmark[13].y * h
    bottom_lip_y = face_landmarks.landmark[14].y * h
    return (bottom_lip_y - top_lip_y) > 20

    def estimate_head_pose(self, face_landmarks, w, h):
    nose = face_landmarks.landmark[1]
    left_eye = face_landmarks.landmark[33]
    right_eye = face_landmarks.landmark[263]
    left_mouth = face_landmarks.landmark[61]
    right_mouth = face_landmarks.landmark[291]

    nose_x, nose_y = nose.x * w, nose.y * h
    eye_center_x = (left_eye.x + right_eye.x) / 2 * w
    eye_center_y = (left_eye.y + right_eye.y) / 2 * h
    mouth_center_x = (left_mouth.x + right_mouth.x) / 2 * w
    mouth_center_y = (left_mouth.y + right_mouth.y) / 2 * h

    dx = nose_x - eye_center_x
    dy = mouth_center_y - eye_center_y

    yaw = dx
    pitch = dy
    roll = 0

    return yaw, pitch, roll

    def rotate_frame(self, frame, angle):
    if angle == 90:
    return cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
    elif angle == 180:
    return cv2.rotate(frame, cv2.ROTATE_180)
    elif angle == 270:
    return cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE)
    else:
    return frame

    def stop(self):
    self._run_flag = False
    self.wait()

    def switch_camera(self):
    self.cap.release()
    self.camera_id = 1 - self.camera_id
    self.cap = cv2.VideoCapture(self.camera_id)

    def rotate_camera(self):
    self.rotation_angle = (self.rotation_angle + 90) % 360

    def save_screenshot(self, frame):
    filename, _ = QFileDialog.getSaveFileName(
    None, "Сохранить скриншот", "", "PNG Files (*.png);;JPEG Files (*.jpg)")
    if filename:
    cv2.imwrite(filename, frame)


    class MainWindow(QWidget):
    def __init__(self):
    super().__init__()
    self.setWindowTitle("zalupa 228 sigma camers")
    self.setFixedSize(1000, 700)
    self.setStyleSheet("""
    QWidget {
    background-color: #121912;
    color: #88cc44;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }
    QLabel#statusLabel {
    font-size: 18px;
    font-weight: bold;
    color: #a0d468;
    min-height: 24px;
    }
    QLabel#fpsLabel {
    font-size: 14px;
    color: #559922;
    }
    QPushButton {
    background-color: #2f4f2f;
    border-radius: 8px;
    padding: 8px 14px;
    font-weight: 600;
    }
    QPushButton:hover {
    background-color: #3a6a3a;
    }
    QCheckBox {
    spacing: 10px;
    font-size: 15px;
    }
    """)

    self.image_label = QLabel()
    self.image_label.setFixedSize(720, 540)
    self.image_label.setStyleSheet("border: 2px solid #228822; border-radius: 10px;")

    controls_group = QGroupBox("Управление")
    controls_layout = QVBoxLayout()

    self.cb_face = QCheckBox("Отслеживание лица (простое)")
    self.cb_face.setChecked(True)
    self.cb_detailed_face = QCheckBox("Детальное лицо (mesh)")
    self.cb_hand = QCheckBox("Отслеживание рук")
    self.cb_fps = QCheckBox("Показывать FPS")
    self.cb_sound = QCheckBox("Звуковые оповещения")

    for cb in [self.cb_face, self.cb_detailed_face, self.cb_hand, self.cb_fps, self.cb_sound]:
    controls_layout.addWidget(cb)
    cb.stateChanged.connect(self.update_tracking)

    self.btn_switch_cam = QPushButton(" Сменить камеру")
    self.btn_switch_cam.clicked.connect(self.switch_camera)
    controls_layout.addWidget(self.btn_switch_cam)

    self.btn_rotate_cam = QPushButton(" Повернуть камеру на 90°")
    self.btn_rotate_cam.clicked.connect(self.rotate_camera)
    controls_layout.addWidget(self.btn_rotate_cam)

    self.btn_screenshot = QPushButton(" Сохранить скриншот")
    self.btn_screenshot.clicked.connect(self.save_screenshot)
    controls_layout.addWidget(self.btn_screenshot)

    self.gesture_label = QLabel("")
    self.gesture_label.setObjectName("statusLabel")
    self.fps_label = QLabel("")
    self.fps_label.setObjectName("fpsLabel")
    self.stats_label = QLabel("Статистика: ")
    self.stats_label.setObjectName("fpsLabel")

    controls_group.setLayout(controls_layout)

    main_layout = QHBoxLayout()
    main_layout.addWidget(self.image_label)
    main_layout.addWidget(controls_group)

    vertical_layout = QVBoxLayout()
    vertical_layout.addLayout(main_layout)
    vertical_layout.addWidget(self.gesture_label)
    vertical_layout.addWidget(self.stats_label)
    vertical_layout.addWidget(self.fps_label)
    vertical_layout.addSpacerItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))

    self.setLayout(vertical_layout)

    self.thread = VideoThread()
    self.thread.change_pixmap_signal.connect(self.update_image)
    self.thread.update_fps_signal.connect(self.update_fps)
    self.thread.gesture_signal.connect(self.update_gesture)
    self.thread.stats_signal.connect(self.update_stats)
    self.thread.start()

    self.update_tracking()

    def update_tracking(self):
    self.thread.track_face = self.cb_face.isChecked()
    self.thread.track_detailed_face = self.cb_detailed_face.isChecked()
    self.thread.track_hands = self.cb_hand.isChecked()
    self.thread.show_fps = self.cb_fps.isChecked()
    self.thread.sound_alerts = self.cb_sound.isChecked()

    def update_image(self, qt_image):
    self.image_label.setPixmap(QPixmap.fromImage(qt_image))

    def update_fps(self, fps):
    if fps > 0:
    self.fps_label.setText(f"FPS: {int(fps)}")
    else:
    self.fps_label.setText("")

    def update_gesture(self, text):
    self.gesture_label.setText(text)

    def update_stats(self, text):
    self.stats_label.setText(text)

    def switch_camera(self):
    self.thread.switch_camera()

    def rotate_camera(self):
    self.thread.rotate_camera()

    def save_screenshot(self):
    pixmap = self.image_label.pixmap()
    if pixmap:
    filename, _ = QFileDialog.getSaveFileName(
    self, "Сохранить скриншот", "", "PNG Files (*.png);;JPEG Files (*.jpg)")
    if filename:
    pixmap.save(filename)

    def closeEvent(self, event):
    self.thread.stop()
    event.accept()


    if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
    GITHUB

    работает ну я тестил на 3.9.10 версии :colobok_amazed:

    opencv-python>=4.5.5
    mediapipe>=0.8.10
    PyQt5>=5.15.4

    numpy>=1.21.0
    СПАСЕБА ЗА ВНИМАНИЕ НА ЭТОМ СОБСТВЕННО ВСЕЕ :colobok_hi:
     
  2. krisssss
    krisssss 23 июн 2025 Заблокирован(а) 10 787 24 дек 2024
    да для слежки за сотрудниками хорошая программа)
     
    1. rasez Автор темы
      krisssss, вово чтоб не втыкали
Загрузка...
Top