尽管使用了线程,Python多摄像头FPS还是非常慢

尽管使用了线程,Python多摄像头FPS还是非常慢,python,python-3.x,multithreading,opencv,tkinter,Python,Python 3.x,Multithreading,Opencv,Tkinter,我尝试用python tkinter和线程动态显示多个实时摄像头。 但我有一个FPS的问题和性能不幸糟糕。该程序使用ip摄像头链接动态创建ui,然后在线程中使用帧。但尽管使用了线程,性能仍然不令人满意。如何提高性能 from functools import partial from PIL import Image, ImageTk import tkinter as tk from tkinter import messagebox from tkinter import font as

我尝试用python tkinter和线程动态显示多个实时摄像头。 但我有一个FPS的问题和性能不幸糟糕。该程序使用ip摄像头链接动态创建ui,然后在线程中使用帧。但尽管使用了线程,性能仍然不令人满意。如何提高性能

from functools import partial

from PIL import Image, ImageTk
import tkinter as tk
from tkinter import messagebox
from tkinter import font as tkFont
import argparse
import datetime
import cv2
import imutils
import os
from threading import Thread


variable = 1
threads = []
camera_urls = ['rtsp://mycamera1.cgi', 'mycamera2.cgi']

video_captures=[]
video_panels=[]
video_currentImages=[]
snaphsot_display_panels=[]
video_labels=[]


class Application:
    def __init__(self, output_path="./"):

        self.output_path = output_path
        self.current_image = None
        self.root = tk.Tk()
        self.root.title("Kamera")
        self.root.protocol('WM_DELETE_WINDOW', self.destructor)

        for indexofUrl in range(len(camera_urls)):
            print("[INFO] URL::" + camera_urls[indexofUrl])
            self.vs = cv2.VideoCapture(camera_urls[indexofUrl])
            video_captures.append(self.vs)
            self.panel = tk.Label(self.root, borderwidth=5, relief="sunken", bg="green")
            self.panel.grid(row=0, column=indexofUrl, padx=20, pady=20)
            video_panels.append(self.panel)
            print("[INFO] STEP:: 1")
            mylabel = tk.Label(text="Kamera " +str(indexofUrl), bg="black", fg="white", font=(None, 15))
            mylabel.grid(row=1, column=indexofUrl)
            print("[INFO] STEP:: 2")
            btn = tk.Button(self.root, text="Görüntüyü kaydet(Kamera "+str(indexofUrl)+")", command=partial(self.take_snapshot,indexofUrl), bg="green", fg='white')
            btn.grid(row=2, column=indexofUrl, padx=20, pady=20)
            print("[INFO] STEP:: 3")
            self.panel3 = tk.Label(self.root)
            self.panel3.grid(row=3, column=indexofUrl)
            print("[INFO] STEP:: 4")
            self.mylabel2 = tk.Label(text="Snapshot bilgileri:", bg="blue", fg="white", font=(None, 15))
            self.mylabel2.grid(row=4, column=indexofUrl)
            video_labels.append(self.mylabel2)
            print("[INFO] STEP:: 5")
            self.panel4 = tk.Label(self.root,relief="sunken", borderwidth=5, bg="black")
            self.panel4.grid(row=5, column=indexofUrl, padx=20, pady=20)
            snaphsot_display_panels.append(self.panel4)

            mythread = Thread(target=self.my_video_loop, args=())
            mythread.daemon = True
            mythread.start()
            threads.append(mythread)
        for t in threads:
            t.join()

        #self.my_video_loop()
        self.thread2 = Thread(target= self.my_video_loop, args=())
        self.thread2.daemon=True
        self.thread2.start()



    def my_video_loop(self):
        for indexOfVideCaptures in range(len(video_captures)):
            ok, frame= video_captures[indexOfVideCaptures].read()
            frame=self.maintain_aspect_ratio_resize(frame , width=400)
            if ok:
                if len(video_currentImages) > len(camera_urls):
                    video_currentImages.clear()
                cv2image = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
                self.current_image = Image.fromarray(cv2image)
                video_currentImages.append(self.current_image)
                imgtk = ImageTk.PhotoImage(image=self.current_image)
                video_panels[indexOfVideCaptures].imgtk =imgtk
                video_panels[indexOfVideCaptures].config(image=imgtk)
        self.root.after(30, self.my_video_loop)


    # Resizes a image and maintains aspect ratio
    def maintain_aspect_ratio_resize(self, image, width=None, height=None, inter=cv2.INTER_AREA):
        # Grab the image size and initialize dimensions
        dim = None
        (h, w) = image.shape[:2]

        # Return original image if no need to resize
        if width is None and height is None:
            return image

        # We are resizing height if width is none
        if width is None:
            # Calculate the ratio of the height and construct the dimensions
            r = height / float(h)
            dim = (int(w * r), height)
        # We are resizing width if height is none
        else:
            # Calculate the ratio of the 0idth and construct the dimensions
            r = width / float(w)
            dim = (width, int(h * r))

        # Return the resized image
        return cv2.resize(image, dim, interpolation=inter)

    def take_snapshot(self, camera):
        ts = datetime.datetime.now()  # current timestamp
        filename = "{}.png".format(ts.strftime("%Y-%m-%d__%H-%M-%S"))  #filename
        p = os.path.join(self.output_path, filename)  # output path
        if camera >= 0:
            if len(video_currentImages) == 0:
                self.take_snapshot(camera)
                # self.root.after(500, self.take_snapshot(camera))
            elif len(video_currentImages) == len(camera_urls):
                video_currentImages[camera].save(p, "PNG")  # save image as jpeg file
                print("[INFO] saved {}".format(filename))
                imgtk3 = ImageTk.PhotoImage(image=video_currentImages[camera])
                snaphsot_display_panels[camera].imgtk =imgtk3
                snaphsot_display_panels[camera].config(image=imgtk3)
                video_labels[camera].config(text=filename.rstrip(".png") + f"\n KAMERA {camera}")

    def destructor(self):
        """ Destroy the root object and release all resources """
        print("[INFO] closing...")
        self.root.destroy()
        for indexcameras in range(len(video_captures)):
            video_captures[indexcameras].release()  # release camera
        cv2.destroyAllWindows()  # it is not mandatory in this application


# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", default="./",
                help="path to output directory to store snapshots (default: current folder")
args = vars(ap.parse_args())

# start the app
print("[INFO] starting...")
pba = Application(args["output"])
pba.root.mainloop()



不确定它是否能回答您的问题,但请检查您不应该在线程化函数中调用
after()
,而是使用while循环。这意味着我应该在while循环中使用线程@ACW1668否,在线程中(即在
my_video_loop()
中)使用while循环而不是
after()
。尝试将摄像头1更换为与摄像头2相同的摄像头。如果有改进,则是摄像机1使用的协议问题。