I am building a push up counter, which will count aloud the number of reps after it detects a rep. I am trying to add pyttsx3 with my current code such that it will count out the number of reps. The code without pyttsx3 works fine, however when I add the pyttsx3 module, the video feed tends to freeze when the code detects a rep. Not only that but it would also unexpectedly stop with the long chain of error messages:
[DEBUG ] <comtypes.client._events.CreateEventReceiver..Sink object at 0x0000028DFE627860>.Release() -> 1
[DEBUG ] <comtypes.client._events.CreateEventReceiver..Sink object at 0x0000028DFE627860>.AddRef() -> 2
[DEBUG ] unimplemented method _ISpeechVoiceEvents_Phoneme called
[DEBUG ] <comtypes.client._events.CreateEventReceiver..Sink object at 0x0000028DFE627860>.Release() -> 1
[DEBUG ] <comtypes.client._events.CreateEventReceiver..Sink object at 0x0000028DFE627860>.AddRef() -> 2
[DEBUG ] unimplemented method _ISpeechVoiceEvents_Viseme called
[DEBUG ] <comtypes.client._events.CreateEventReceiver..Sink object at 0x0000028DFE627860>.Release() -> 1
[DEBUG ] <comtypes.client._events.CreateEventReceiver..Sink object at 0x0000028DFE627860>.AddRef() -> 2
[DEBUG ] <comtypes.client._events.CreateEventReceiver..Sink object at 0x0000028DFE627860>.Release() -> 1
Process finished with exit code -1
for reference, this is part of my code without pyttsx3:
def load_video(self, dt):
ret, frame = self.capture.read()
if ret:
# Run pose estimation
image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.pose.process(image_rgb)
# Extract relevant landmarks for push-up detection
if results.pose_landmarks is not None:
landmarks = results.pose_landmarks.landmark
left_shoulder = landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value]
right_shoulder = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value]
left_elbow = landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value]
right_elbow = landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW.value]
left_wrist = landmarks[mp_pose.PoseLandmark.LEFT_WRIST.value]
right_wrist = landmarks[mp_pose.PoseLandmark.RIGHT_WRIST.value]
left_hip = landmarks[mp_pose.PoseLandmark.LEFT_HIP.value]
right_hip = landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value]
left_knee = landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value]
right_knee = landmarks[mp_pose.PoseLandmark.RIGHT_KNEE.value]
# Calculate angles for push-up detection
angle_left = self.calculate_angle([left_shoulder.x, left_shoulder.y], [left_elbow.x, left_elbow.y],
[left_wrist.x, left_wrist.y])
angle_right = self.calculate_angle([right_shoulder.x, right_shoulder.y], [right_elbow.x, right_elbow.y],
[right_wrist.x, right_wrist.y])
angle2 = self.calculate_angle([left_shoulder.x, left_shoulder.y], [left_hip.x, left_hip.y],
[left_knee.x, left_knee.y])
angle3 = self.calculate_angle([right_shoulder.x, right_shoulder.y], [right_hip.x, right_hip.y],
[right_knee.x, right_knee.y])
# Update stage based on angle criteria
if angle_left < 90 and angle_right < 90 and angle2 > 165 and angle3 > 165:
self.stage = "down"
else:
self.stage = "up"
# Increment counter if criteria met
if self.stage == "up" and self.prev_stage == "down":
self.counter += 1
self.prev_stage = self.stage
This is the code i tried to come up with:
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDRaisedButton
from kivy.graphics.texture import Texture
from kivy.uix.image import Image
from kivy.clock import Clock
import cv2
import mediapipe as mp
import numpy as np
import pyttsx3
mp_drawing = mp.solutions.drawing_utils
mp_pose = mp.solutions.pose
class App(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.engine = pyttsx3.init()
def load_video(self, dt):
ret, frame = self.capture.read()
if ret:
# Run pose estimation
image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.pose.process(image_rgb)
# Extract relevant landmarks for push-up detection
if results.pose_landmarks is not None:
landmarks = results.pose_landmarks.landmark
left_shoulder = landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value]
right_shoulder = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value]
left_elbow = landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value]
right_elbow = landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW.value]
left_wrist = landmarks[mp_pose.PoseLandmark.LEFT_WRIST.value]
right_wrist = landmarks[mp_pose.PoseLandmark.RIGHT_WRIST.value]
left_hip = landmarks[mp_pose.PoseLandmark.LEFT_HIP.value]
right_hip = landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value]
left_knee = landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value]
right_knee = landmarks[mp_pose.PoseLandmark.RIGHT_KNEE.value]
# Calculate angles for push-up detection
angle_left = self.calculate_angle([left_shoulder.x, left_shoulder.y], [left_elbow.x, left_elbow.y], [left_wrist.x, left_wrist.y])
angle_right = self.calculate_angle([right_shoulder.x, right_shoulder.y], [right_elbow.x, right_elbow.y], [right_wrist.x, right_wrist.y])
angle2 = self.calculate_angle([left_shoulder.x, left_shoulder.y], [left_hip.x, left_hip.y], [left_knee.x, left_knee.y])
angle3 = self.calculate_angle([right_shoulder.x, right_shoulder.y], [right_hip.x, right_hip.y], [right_knee.x, right_knee.y])
# Update stage based on angle criteria
if angle_left < 90 and angle_right < 90 and angle2 > 165 and angle3 > 165:
self.stage = "down"
else:
self.stage = "up"
# Increment counter if criteria met
if self.stage == "up" and self.prev_stage == "down":
self.counter += 1
# Speak the current count
self.engine.say(f"Rep number {self.counter}")
self.engine.runAndWait()
self.prev_stage = self.stage
def on_stop(self):
# Release pyttsx3 engine
self.engine.stop()
# Release OpenCV video capture and Mediapipe pose
self.capture.release()
self.pose.close()
super().on_stop()
if __name__ == '__main__':
App().run()
After I faced the errors, I removed the self.engine = pyttsx3.init()
, self.engine.stop()
, still didnt work.
I also tried creating a whole different function, to no use:
def speak_count_async(self, count):
def speak():
self.engine.say(f"Rep number {count}")
self.engine.runAndWait()
Lastly I also tried logging, also got the same errors:
class App(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Initialize pyttsx3 with 'sapi5' engine and suppress debug logs
self.engine = pyttsx3.init(driverName='sapi5')
logging.getLogger('pyttsx3').setLevel(logging.WARNING)
Im not really sure why these errors are happening anymore, should i use a different tts module? Please help me out! Thank you!!
Devansh Singhal is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.