I am working on Vision-Based American Sign Language Converter Application using MediaPipe and OpenCV in python. As you may know, in webcam, we use a while loop for continuous hand detection of our hand. Now the problem was that when I added audio function for the detected gesture using pyttx3 the webcam always got struck during the execution of pyttsx3 engine function. To resolve that issue, I used threading and made a thread for that audio related part and put that thread inside that webcam while loop. But now the problem is that, the "Runtime Error: loop is already started" continuously appears in the terminal.
I have made a model code for my problem. I know the problem is that the threading function is calling the speak function again and again, and inside the speak function I have used 'runAndWait()' method, which is giving the error that loop is already started. Please look into this matter. I have been looking for the solution for two weeks. I have tried every possible thing on my own.
import pyttsx3
from threading import Thread
import random
engine = pyttsx3.init()
def speak(text):
engine.say(text)
engine.runAndWait()
while True:
l = ['A', 'B', 'C', 'D', 'E']
a = random.choice(l)
print(a)
t = Thread(target=speak, args=(a,))
t.start()
#engine.stop()
CodePudding user response:
As you have mentioned, the problem is that you used threading which calls the function over and over again. This is problematic. First of all, you are creating 100s of Threading instances each second which is highly inefficient. Secondly, you are creating a backlog of 1000s of calls to be made to the "engine" which will take hours to finish. Despite these, it is possible to change your code and make it run the way you intend to:
import pyttsx3
from threading import Thread
import random
from queue import Queue
def speak(q):
engine = pyttsx3.init()
while True:
if q.empty() is False:
a = q.get()
engine.say(a)
engine.runAndWait()
else:
pass
queue= Queue()
t = Thread(target=speak, args=(queue,))
t.start()
while True:
l = ['A', 'B', 'C', 'D', 'E']
a = random.choice(l)
queue.put(a)
print(a)
Essentially, you are making a new thread (only one) that communicates with the pyttsx3
. Each iteration, you will put whatever you want to read into the queue and the system will take them one by one (in a first come first serve manner) and read them. This will only need one extra thread, therefore you won't need to create 100s of Thread instances.
However, this method still creates a backlog of 1000s of speeches to be made. I do not have experience with ASL analysis. But the way I would approach this problem would be to use a separate thread to analyze the last 2~5 seconds of the video and if the hand gesture is detected, it would initialize the speak command. This will make the speech a couple of seconds behind the video which is completely fine in this scenario.