鱼C论坛

 找回密码
 立即注册
查看: 1832|回复: 6

[已解决]求助pyqt多线程卡死的问题

[复制链接]
发表于 2023-2-28 11:27:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
各位大佬,我在主程序中调用另一个模块的摄像头录制,卡死在webcam.py的start_capture的while循环中了,主程序中的停止线程(StopCapturingThread)无法触发,需要如何修改呢?
相关代码如下,感谢各位大佬的帮助!:

-------------main.py-------------
from UIs.mainwindow import Ui_Form
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from Module.VideoRecording.webcam import WebCam
from Module.SmartEyePro.external_interfaces import ExternalInterface
import os
import time


class InteractiveFeatures(WebCam, ExternalInterface):
    def __init__(self):
        self.webcam = None
        self.sep = None
        self.biosignalsplux = None
        self.brainproducts = None
        self.connected_dict = {'webcam': False, 'sep': False, 'biosignalsplux': False, 'brainproducts': False}
        self.init_list = []

        self.sep_logname = None
        self.sep_last_ip = None

    # 设置摄像头交互功能
    def webcam_init(self):
        VideoPath = r'D:\PycharmProjects\IntelligentAssessment\inset'
        PNGPath = r'D:\PycharmProjects\IntelligentAssessment\inset'
        LogPath = r'D:\PycharmProjects\IntelligentAssessment\inset'
        CSVPath = r'D:\PycharmProjects\IntelligentAssessment\inset'
        IP = '192.168.1.2'
        self.webcam = WebCam(VideoPath, PNGPath, CSVPath, IP)
        self.connected_dict['webcam'] = True

    def webcam_disconnect(self):
        self.webcam = None
        self.connected_dict['webcam'] = False

    def _webcam_start(self):
        self.webcam.start_capture()

    def _webcam_stop(self):
        self.webcam.stop_capture()

    # 选中设备开始采集
    def start_capture(self):
        for progress, state in self.connected_dict.items():
            if state:
                self.init_list.append(progress)
        init_number = len(self.init_list)
        for i in range(init_number):
            code = "t{} = Thread(target=self._{}_start)".format(i + 1, self.init_list[i])
            exec(code)
        for i in range(init_number):
            code = "t{}.start()".format(i + 1)
            eval(code)
        for i in range(init_number):
            code = "t{}.join()".format(i + 1)
            eval(code)

    # 选中设备结束采集
    def stop_capture(self):
        init_number = len(self.init_list)
        for i in range(init_number):
            code = "self._{}_stop()".format(self.init_list[i])
            eval(code)
        for i in range(init_number):
            code = "self.{}_init()".format(self.init_list[i])
            eval(code)
        self.init_list = []

    # 生成当前时间
    def get_now(self):
        now = time.localtime()
        nowt = time.strftime("%Y-%m-%d-%H-%M-%S", now)
        return nowt


# 开始采集线程
class StartCapturingThread(QThread):

    startCapturingSignal = Signal()

    def __init__(self, parent=None):
        super(StartCapturingThread, self).__init__(parent)

    def run(self):
        self.startCapturingSignal.emit()


# 结束采集线程
class StopCapturingThread(QThread):

    stopCapturingSignal = Signal()

    def __init__(self, parent=None):
        super(StopCapturingThread, self).__init__(parent)

    def run(self):
        self.stopCapturingSignal.emit()


class MyMainForm(QMainWindow, Ui_Form, InteractiveFeatures, StartCapturingThread, StopCapturingThread):
    def __init__(self, parent=None):
        super(MyMainForm, self).__init__(parent)
        self.start_capturing_thread = StartCapturingThread()
        self.stop_capturing_thread = StopCapturingThread()
        self.interactive_features = InteractiveFeatures()
        self.setupUi(self)
        self.pushButton.clicked.connect(self.btn1clicked)
        self.pushButton_2.clicked.connect(self.btn2clicked)
        self.pushButton_5.clicked.connect(self.btn5clicked)
        self.pushButton_6.clicked.connect(self.btn6clicked)
        self.pushButton_15.clicked.connect(self.Start)
        self.pushButton_16.clicked.connect(self.Stop)
        self.pushButton_11.clicked.connect(self.btn11clicked)

    def btn1clicked(self):
        IP = self.sep_ip.text()
        self.interactive_features.sep_logname = self.sep_logfile.text()
        ans = self.interactive_features.sep_init(IP)
        if ans:
            self.label_9.setPixmap(QPixmap(u"SrcPics/connect_green.svg"))
            self.label_10.setPixmap(QPixmap(u"SrcPics/disconnect_black.svg"))
            self.sep_ip.setEnabled(False)
            self.sep_logfile.setEnabled(False)
        else:
            QMessageBox.information(self, "连接失败", "连接失败,请检查设备后重试!")

    def btn5clicked(self):
        self.label_21.setPixmap(QPixmap(u"SrcPics/connect_green.svg"))
        self.label_22.setPixmap(QPixmap(u"SrcPics/disconnect_black.svg"))
        self.camera_ip.setEnabled(False)
        self.camera_frequency.setEnabled(False)
        self.interactive_features.webcam_init()

    def btn2clicked(self):
        self.label_9.setPixmap(QPixmap(u"SrcPics/connect_black.svg"))
        self.label_10.setPixmap(QPixmap(u"SrcPics/disconnect_red.svg"))
        self.sep_ip.setEnabled(True)
        self.sep_logfile.setEnabled(True)
        self.interactive_features.sep_disconnect()

    def btn6clicked(self):
        self.label_21.setPixmap(QPixmap(u"SrcPics/connect_black.svg"))
        self.label_22.setPixmap(QPixmap(u"SrcPics/disconnect_red.svg"))
        self.camera_ip.setEnabled(True)
        self.camera_frequency.setEnabled(True)
        self.interactive_features.webcam_disconnect()

    def btn11clicked(self):
        self.sep_logfile.setText(self.interactive_features.get_now())

    def Start(self):
        # self.start_capturing_thread = StartCapturingThread()
        self.start_capturing_thread.startCapturingSignal.connect(self.interactive_features.start_capture)
        self.start_capturing_thread.start()
        self.pushButton_15.setEnabled(False)
        self.pushButton_17.setEnabled(False)

    def Stop(self):
        # self.stop_capturing_thread = StopCapturingThread()
        self.stop_capturing_thread.stopCapturingSignal.connect(self.interactive_features.stop_capture)
        self.stop_capturing_thread.start()
        self.pushButton_15.setEnabled(True)
        self.pushButton_17.setEnabled(True)



-------------webcam.py-------------
"""
下列代码包括如下功能:
    1.start_capture(video_path):在video_path目录下录制网络摄像头拍摄的视频
    2.analysis2csv(video_path):分析录制视频表情,将其输出给out.csv
    3.screenshot_emotion(joy, surprise, fear, video_path, png_path):将video_path下的视频中joy、surprise、fear三种情绪最大的
                                                                    帧输出至png_path
    4.web_video(video_path, png_path):上述功能总函数,需输入video_path、png_path两个参数
"""
import sys
import os
cwd = os.getcwd()
cac_path = os.path.join(cwd, 'Module', 'CacEmotions')
sys.path.append(cac_path)
from Module.CacEmotions.cac_emotion import getEmotioner, emotion_flag, express_flag
import cv2
import pandas as pd
from Module import CAPTUREFLAG

class WebCam:
    def __init__(self, video_path, png_path, csv_path, IP):
        self.video_path = video_path
        self.png_path = png_path
        self.csv_path = csv_path
        self.ip = IP
        self.capture = True
        self.is_connected = False

    def start_capture(self):
        # 初始化摄像头
        cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
        fourcc = cv2.VideoWriter_fourcc(*'XVID')
        size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
        num = 0
        print('Starting capture video!')
        while cap.isOpened():
            isSuccess, frame = cap.read()
            if isSuccess and num == 0:
                filename = self.video_path + '\\capture.avi'
                video_writer = cv2.VideoWriter(filename, fourcc, 10, size)
            video_writer.write(frame)
            num = num + 1
            if not CAPTUREFLAG.captureflag:
                break
        cap.release()
        cv2.destroyAllWindows()

    # TODO: 运行start_capture时,stop_capture函数无法触发,建立新的线程解决该问题
    def stop_capture(self):
        self.capture = False
        joy_max, surprise_max, fear_max = self.analysis2csv()
        self.screenshot_emotion(joy_max, surprise_max, fear_max)
最佳答案
2023-3-1 12:09:48
看你代码start_capture方法里退出循环的标志位是CAPTUREFLAG.captureflag,但是stop_capture方法里却把self.capture设置为False,这么做能结束循环吗???
要么 start_capture 里if not self.capture ,要么 stop_capture 里 CAPTUREFLAG.captureflag = False

还有你贴出来的程序都不能运行,目录结构都不知道是啥,自写模块也不完整,CAPTUREFLAG.captureflag 都不知道到底是个啥,别人怎么帮你解决问题?

我想问的是程序卡死在我调用的模块的while循环当中了,我的主程序中有开始线程和结束线程,但结束线程无法触发,该如何解决这个问题

你说的是主界面卡住无响应还是单纯地结束线程的时候没反应?如果是前者,你应该用新线程执行你的另一个模块,在主线程执行结束方法,而不是反过来;如果是后者,请参考这个回答的前面两行

最后想说的是程序不要用 exec 和 eval 执行代码,这么写调试困难,也是十分不优雅不Pythonic的写法,除非你想执行用户从外部输入的代码。我是看到这里不想再往下看了,追溯困难
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-2-28 15:04:40 | 显示全部楼层
依赖的库过多的时候最好放一个依赖库的版本(requirements.txt)上来,别人才好帮你 debug,

不然光靠读代码是很费时间的,没多少人愿意这样去做
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-3-1 10:39:27 | 显示全部楼层
isdkz 发表于 2023-2-28 15:04
依赖的库过多的时候最好放一个依赖库的版本(requirements.txt)上来,别人才好帮你 debug,

不然光靠读 ...

我想问的是程序卡死在我调用的模块的while循环当中了,我的主程序中有开始线程和结束线程,但结束线程无法触发,该如何解决这个问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-3-1 12:09:48 | 显示全部楼层    本楼为最佳答案   
看你代码start_capture方法里退出循环的标志位是CAPTUREFLAG.captureflag,但是stop_capture方法里却把self.capture设置为False,这么做能结束循环吗???
要么 start_capture 里if not self.capture ,要么 stop_capture 里 CAPTUREFLAG.captureflag = False

还有你贴出来的程序都不能运行,目录结构都不知道是啥,自写模块也不完整,CAPTUREFLAG.captureflag 都不知道到底是个啥,别人怎么帮你解决问题?

我想问的是程序卡死在我调用的模块的while循环当中了,我的主程序中有开始线程和结束线程,但结束线程无法触发,该如何解决这个问题

你说的是主界面卡住无响应还是单纯地结束线程的时候没反应?如果是前者,你应该用新线程执行你的另一个模块,在主线程执行结束方法,而不是反过来;如果是后者,请参考这个回答的前面两行

最后想说的是程序不要用 exec 和 eval 执行代码,这么写调试困难,也是十分不优雅不Pythonic的写法,除非你想执行用户从外部输入的代码。我是看到这里不想再往下看了,追溯困难
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-3-1 13:45:49 | 显示全部楼层
hrpzcf 发表于 2023-3-1 12:09
看你代码start_capture方法里退出循环的标志位是CAPTUREFLAG.captureflag,但是stop_capture方法里却把self ...

感谢回复与帮助!
1是贴错代码了 CAPTUREFLAG.captureflag = False 是已经删掉的
2“你说的是主界面卡住无响应还是单纯地结束线程的时候没反应?如果是前者,你应该用新线程执行你的另一个模块,在主线程执行结束方法,而不是反过来”应该是正确的解决方法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-3-1 14:04:21 | 显示全部楼层
hrpzcf 发表于 2023-3-1 12:09
看你代码start_capture方法里退出循环的标志位是CAPTUREFLAG.captureflag,但是stop_capture方法里却把self ...

十分感谢!已解决
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-3-2 09:10:19 | 显示全部楼层

请将解决问题的楼层设为最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-2 01:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表