MediaPipe and YOLOv8 Integration: An Advanced Computer Vision Application
Learn how to combine MediaPipe and YOLOv8 to build a complete computer vision application.
I
InSkillCoach
· min
MediaPipe and YOLOv8 Integration: An Advanced Computer Vision Application
A complete guide to building an application that combines pose detection with MediaPipe and object detection with YOLOv8.
1. Initial Setup
# Installing dependencies
pip install mediapipe ultralytics opencv-python numpy
# Importing libraries
import mediapipe as mp
from ultralytics import YOLO
import cv2
import numpy as np
import time
from threading import Thread
from queue import Queue
2. Application Architecture
2.1 Base Classes
class PoseDetector:
def __init__(self):
self.mp_pose = mp.solutions.pose
self.pose = self.mp_pose.Pose(
min_detection_confidence=0.5,
min_tracking_confidence=0.5
)
self.mp_draw = mp.solutions.drawing_utils
def detect(self, image):
# Convert to RGB
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Pose detection
results = self.pose.process(image_rgb)
# Draw landmarks
if results.pose_landmarks:
self.mp_draw.draw_landmarks(
image,
results.pose_landmarks,
self.mp_pose.POSE_CONNECTIONS
)
return image, results.pose_landmarks
class ObjectDetector:
def __init__(self):
self.model = YOLO('yolov8n.pt')
def detect(self, image):
# Object detection
results = self.model(image)
# Process results
for result in results:
boxes = result.boxes
for box in boxes:
# Box coordinates
x1, y1, x2, y2 = box.xyxy[0]
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
# Confidence
confidence = float(box.conf[0])
# Class
class_id = int(box.cls[0])
class_name = self.model.names[class_id]
# Draw the box
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
# Add the text
label = f"{class_name} {confidence:.2f}"
cv2.putText(image, label, (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
return image
3. Multithreaded Processing
3.1 Frame Manager
class FrameManager:
def __init__(self, max_queue_size=2):
self.frame_queue = Queue(maxsize=max_queue_size)
self.result_queue = Queue(maxsize=max_queue_size)
def add_frame(self, frame):
if not self.frame_queue.full():
self.frame_queue.put(frame)
def get_frame(self):
if not self.frame_queue.empty():
return self.frame_queue.get()
return None
def add_result(self, result):
if not self.result_queue.full():
self.result_queue.put(result)
def get_result(self):
if not self.result_queue.empty():
return self.result_queue.get()
return None
3.2 Workers
class PoseWorker(Thread):
def __init__(self, frame_manager, detector):
super().__init__()
self.frame_manager = frame_manager
self.detector = detector
self.running = True
def run(self):
while self.running:
frame = self.frame_manager.get_frame()
if frame is not None:
# Pose detection
processed_frame, landmarks = self.detector.detect(frame)
self.frame_manager.add_result((processed_frame, landmarks))
class ObjectWorker(Thread):
def __init__(self, frame_manager, detector):
super().__init__()
self.frame_manager = frame_manager
self.detector = detector
self.running = True
def run(self):
while self.running:
frame = self.frame_manager.get_frame()
if frame is not None:
# Object detection
processed_frame = self.detector.detect(frame)
self.frame_manager.add_result((processed_frame, None))
4. Main Application
4.1 Configuration
class Application:
def __init__(self):
# Initialize the detectors
self.pose_detector = PoseDetector()
self.object_detector = ObjectDetector()
# Initialize the frame manager
self.frame_manager = FrameManager()
# Initialize the workers
self.pose_worker = PoseWorker(self.frame_manager, self.pose_detector)
self.object_worker = ObjectWorker(self.frame_manager, self.object_detector)
# Camera configuration
self.cap = cv2.VideoCapture(0)
# Control variables
self.running = True
self.current_mode = 'both' # 'pose', 'object', 'both'
4.2 Main Loop
def run(self):
# Start the workers
self.pose_worker.start()
self.object_worker.start()
while self.running:
success, frame = self.cap.read()
if not success:
continue
# Add the frame to the manager
self.frame_manager.add_frame(frame.copy())
# Retrieve the results
pose_result = self.frame_manager.get_result()
object_result = self.frame_manager.get_result()
# Display the results
if pose_result is not None and object_result is not None:
pose_frame, pose_landmarks = pose_result
object_frame, _ = object_result
# Combine the results
if self.current_mode == 'both':
# Overlay the results
combined_frame = cv2.addWeighted(
pose_frame, 0.5, object_frame, 0.5, 0
)
cv2.imshow('Combined Detection', combined_frame)
elif self.current_mode == 'pose':
cv2.imshow('Pose Detection', pose_frame)
else:
cv2.imshow('Object Detection', object_frame)
# Handle key presses
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
self.running = False
elif key == ord('p'):
self.current_mode = 'pose'
elif key == ord('o'):
self.current_mode = 'object'
elif key == ord('b'):
self.current_mode = 'both'
# Cleanup
self.cleanup()
4.3 Cleanup
def cleanup(self):
# Stop the workers
self.pose_worker.running = False
self.object_worker.running = False
self.pose_worker.join()
self.object_worker.join()
# Release resources
self.cap.release()
cv2.destroyAllWindows()
5. Advanced Features
5.1 Interaction Analysis
def analyze_interaction(pose_landmarks, object_detections):
if pose_landmarks is None or object_detections is None:
return None
# Extract the pose keypoints
left_hand = np.array([
pose_landmarks.landmark[mp_pose.PoseLandmark.LEFT_WRIST.value].x,
pose_landmarks.landmark[mp_pose.PoseLandmark.LEFT_WRIST.value].y
])
right_hand = np.array([
pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_WRIST.value].x,
pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_WRIST.value].y
])
# Analyze interactions with the detected objects
interactions = []
for detection in object_detections:
box_center = np.array([
(detection[0] + detection[2]) / 2,
(detection[1] + detection[3]) / 2
])
# Compute distances
left_distance = np.linalg.norm(left_hand - box_center)
right_distance = np.linalg.norm(right_hand - box_center)
# Detect interactions
if left_distance < 0.1 or right_distance < 0.1:
interactions.append({
'object': detection[4],
'hand': 'left' if left_distance < right_distance else 'right',
'distance': min(left_distance, right_distance)
})
return interactions
5.2 Advanced Visualization
def visualize_results(frame, pose_landmarks, object_detections, interactions):
# Draw the pose landmarks
if pose_landmarks:
mp_draw.draw_landmarks(
frame,
pose_landmarks,
mp_pose.POSE_CONNECTIONS
)
# Draw the object detection boxes
for detection in object_detections:
x1, y1, x2, y2 = detection[:4]
cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
# Visualize the interactions
if interactions:
for interaction in interactions:
# Draw a line between the hand and the object
hand_point = left_hand if interaction['hand'] == 'left' else right_hand
cv2.line(
frame,
(int(hand_point[0] * frame.shape[1]), int(hand_point[1] * frame.shape[0])),
(int(box_center[0] * frame.shape[1]), int(box_center[1] * frame.shape[0])),
(0, 0, 255),
2
)
return frame
6. Performance Optimization
6.1 Memory Management
def optimize_memory():
# Configuration for optimal memory usage
pose_detector = PoseDetector()
object_detector = ObjectDetector()
# Reduce frame size
def resize_frame(frame):
return cv2.resize(frame, (640, 480))
# Periodic queue cleanup
def cleanup_queues():
while not frame_manager.frame_queue.empty():
frame_manager.frame_queue.get()
while not frame_manager.result_queue.empty():
frame_manager.result_queue.get()
6.2 GPU Acceleration
def enable_gpu_acceleration():
# Configuration for GPU usage
import torch
if torch.cuda.is_available():
# Configure YOLO for the GPU
object_detector.model.to('cuda')
# Configure MediaPipe for the GPU
pose_detector.pose = mp_pose.Pose(
min_detection_confidence=0.5,
min_tracking_confidence=0.5,
model_complexity=1,
enable_segmentation=False
)
7. Best Practices
-
Resource Management
- Use multithreading for detections
- Implement a caching system
- Clean up memory regularly
-
Optimization
- Reduce frame size
- Use GPU acceleration
- Adjust detection frequencies
-
User Interface
- Provide intuitive controls
- Display performance metrics
- Allow mode switching in real time
Conclusion
Key takeaways:
- Effective integration of MediaPipe and YOLOv8
- Multithreaded processing for better performance
- Analysis of interactions between pose and objects
- Flexible user interface
Recommendations:
- Optimize memory usage
- Use GPU acceleration
- Implement robust error handling
- Add customization features
About InSkillCoach
Training and technology expert
Coach specializing in advanced technologies and AI, backed by GNeurone Inc.
Certifications:
- AWS Certified Solutions Architect – Professional
- Google Cloud certifications
- Microsoft Certified: DevOps Engineer Expert
- Certified Kubernetes Administrator (CKA)
- CompTIA Security+
804
97
Comments
Comments are powered by GitHub Discussions
Sign in with GitHub to join the discussion