运行 在 while 循环中使用线程的时间错误

Run Time error on using Threading in a while loop

我正在 python 中使用 MediaPipe 和 OpenCV 开发基于视觉的美国手语转换器应用程序。如您所知,在网络摄像头中,我们使用 while 循环来连续检测我们的手。现在的问题是,当我使用 pyttx3 为检测到的手势添加音频功能时,在执行 pyttsx3 引擎功能期间网络摄像头总是被击中。 为了解决这个问题,我使用了线程并为音频相关部分创建了一个线程,并将该线程放在网络摄像头的 while 循环中。 但现在的问题是,“运行时错误:循环已经开始”不断出现在终端中。

我已经为我的问题制作了模型代码。我知道问题是线程函数一次又一次地调用 speak 函数,并且在 speak 函数中我使用了 'runAndWait()' 方法,这给出了循环已经开始的错误。 请调查此事。我一直在寻找解决方案两个星期。我已经自己尝试了所有可能的事情。

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()

正如您所提到的,问题在于您使用了线程,它一遍又一遍地调用该函数。这是有问题的。首先,您每秒创建 100 个 Threading 实例,这是非常低效的。其次,您正在创建对“引擎”进行的 1000 次调用的积压,这将需要数小时才能完成。尽管如此,还是可以更改您的代码并使其 运行 成为您想要的方式:

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)

本质上,您正在创建一个与 pyttsx3 通信的新线程(只有一个)。每次迭代,您将要读取的任何内容放入队列中,系统将一个一个地读取它们(以先到先得的方式)并读取它们。这将只需要一个额外的线程,因此您不需要创建 100 个 Thread 实例。

但是,这种方法仍然会造成 1000 篇演讲的积压。我没有 ASL 分析经验。但是我解决这个问题的方法是使用一个单独的线程来分析视频的最后 2 到 5 秒,如果检测到手势,它将初始化说话命令。这将使演讲比视频晚几秒钟,这在这种情况下完全没问题。

编辑:解决这个问题的更好方法,伪代码:

fps = 30       // # of frames per second for the video (assumed 30)
sec = 2        // Number of seconds for each analysis
counter=1      // This counts the frame from previous analysis
frameBatch =[] // This includes the frames for the last 2 sec that need to be 
               // analyzed. Its better to use *Numpy*
while true:
    frame = *Get the frame from the webcam*
    if counter % (fpa*sec)==0:
        analyseAndSpeak(frameBatch) // This analyse method will analyze the 
                                    // last 2 seconds and then send the 
                                    // analysis to the speak engine

         counter =1                 // Resets the counter 
         frameBatch =[]             // Empties the frameBatch
    else:
         frameBatch.append(frame)   // Adds the current frame to the batch
         counter +=1

使用这种方法,每两秒的视频,就会存储帧,然后将其转储到分析函数中,该函数也会读取结果。这个函数应该在不同的线程上。此后,开始新的两秒并继续。您应该玩弄这些数字,并尝试调整语速以不落后于视频。

你还应该小心 while 循环,因为它非常快,所以要么使用不同的方法,要么你的 FPS 应该非常高。如果您的 FPS 很高(超过 100),您可以从 frameBatch 中每隔一帧丢弃一次以提高效率。希望这有帮助。