python 如何保持imshow()窗口的响应,即使帧处理需要几秒钟?

egdjgwm8  于 2023-02-21  发布在  Python
关注(0)|答案(1)|浏览(272)

我想实现具有视频去雾能力的this库,我只有CPU,但我期望没有GPU的结果会很好,因为DCP的视频输出,或任何其他去雾算法工作良好。
所以我开发了这个代码:

import cv2
import torch
import numpy as np
import torch.nn as nn
import math

class dehaze_net(nn.Module):

    def __init__(self):
        super(dehaze_net, self).__init__()

        self.relu = nn.ReLU(inplace=True)
    
        self.e_conv1 = nn.Conv2d(3,3,1,1,0,bias=True) 
        self.e_conv2 = nn.Conv2d(3,3,3,1,1,bias=True) 
        self.e_conv3 = nn.Conv2d(6,3,5,1,2,bias=True) 
        self.e_conv4 = nn.Conv2d(6,3,7,1,3,bias=True) 
        self.e_conv5 = nn.Conv2d(12,3,3,1,1,bias=True) 
        
    def forward(self, x):
        source = []
        source.append(x)

        x1 = self.relu(self.e_conv1(x))
        x2 = self.relu(self.e_conv2(x1))

        concat1 = torch.cat((x1,x2), 1)
        x3 = self.relu(self.e_conv3(concat1))

        concat2 = torch.cat((x2, x3), 1)
        x4 = self.relu(self.e_conv4(concat2))

        concat3 = torch.cat((x1,x2,x3,x4),1)
        x5 = self.relu(self.e_conv5(concat3))

        clean_image = self.relu((x5 * x) - x5 + 1) 
        
        return clean_image

model = dehaze_net()

model.load_state_dict(torch.load('snapshots/dehazer.pth',map_location=torch.device('cpu')))

device = torch.device('cpu')
model.to(device)

cap = cv2.VideoCapture(0)

while cap.isOpened():
    ret, frame = cap.read()

    if ret:
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        frame = torch.from_numpy(frame.transpose((2, 0, 1))).float().unsqueeze(0) / 255.0
        frame = frame.to(device)

        with torch.no_grad():
            dehazed_frame = model(frame).squeeze().cpu().numpy()

        dehazed_frame = (dehazed_frame * 255).clip(0, 255).transpose((1, 2, 0)).astype(np.uint8)
        dehazed_frame = cv2.cvtColor(dehazed_frame, cv2.COLOR_RGB2BGR)

        cv2.imshow('Dehazed Frame', dehazed_frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

cap.release()

cv2.destroyAllWindows()

这是一个单文件代码,只需从原始源(* MayankSingal/PyTorch-Image-Dehazing *)下载snapshots/dehazer.pth
我下载并执行了代码。
暂时让我在镜头前展示一张纸,

问题:

问题是
1.显示视频的窗口冻结,直到它获得新的帧,即:帧1---〉冻结---〉帧2 ...,下面是一些示例:

1秒钟内窗口显示良好

窗口5秒内无响应/挂起/冻结...
1.显示视频的窗口显示具有长延迟的帧,即一帧大约需要5秒
我期待流畅的实时输出(即使每秒帧数是1或2也没问题),但我不同意"无响应"窗口,我觉得我/作者放置的代码有一些缺陷/问题/漏洞。如果我使用任何其他代码,如DCP,就没有问题。那么是什么部分导致无响应,如何解决?

wwtsj6pe

wwtsj6pe1#

GUI需要定期运行事件处理。如果不经常运行,GUI会明显变得没有响应。大多数操作系统都会为你注意到这一点,并提醒你程序变得没有响应。
GUI是基于事件的。任何密集的计算必须在事件循环之外执行,例如在线程中。
在您的程序中,情况并非如此,因为您在调用waitKey()的同一个循环中执行(计算密集型)推理,waitKey()是OpenCV中执行GUI事件处理的函数。
下面是如何使用螺纹的简要说明:

import cv2 as cv
import threading
import queue

def worker_function(stop_event, result_queue):
    cap = cv.VideoCapture()
    assert cap.isOpened()

    while not stop_event.is_set():
        (success, frame) = cap.read()
        if not success: break

        ... # do your inference here

        result_queue.put(result_frame)

    cap.release()

if __name__ == "__main__":
    stop_event = threading.Event()
    result_queue = queue.Queue(maxsize=1)
    worker_thread = threading.Thread(
        target=worker_function, args=(stop_event, result_queue))
    worker_thread.start()

    cv.namedWindow("window", cv.WINDOW_NORMAL)

    while True:
        # handle new result, if any
        try:
            result_frame = result_queue.get_nowait()
            cv.imshow("window", result_frame)
            result_queue.task_done()
        except queue.Empty:
            pass

        # GUI event processing
        key = cv.waitKey(10)
        if key in (13, 27): # Enter, Escape
            break
    
    stop_event.set()
    worker_thread.join()

我没有测试这个,但这个想法是合理的。

相关问题