python - 尽管使用线程,Python Multi camera FPS 还是很慢
问题描述
我尝试使用线程在 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()
解决方案
推荐阅读
- java - 带有 void * 参数的 JNA 回调函数
- javascript - 图像不会在服务器上加载,而是在本地加载(heroku)
- scala - 如何在使用 scala 播放框架进行 json 转换时摆脱额外的转义字符?
- c# - 具有连接池的 ADO.NET 中的超时错误
- python - 访问自定义的动态类属性会引发错误 - kivy
- zugferd - Konik 是否已经支持包含 XRechnung 作为可选模式的 ZugFERD 2.1?
- c++ - 设置插入迭代器超出范围
- bash - 通过 kubectl 获取上次成功完成 cronjob 的时间戳
- chef-infra - 刀和berkshelf的区别?
- javascript - 当我尝试使用数据库中的帐户登录时,我的 ajax 调用不会进入 succes 事件。有人有什么建议吗?