簡體   English   中英

如何使用使用 Vimba SDK 的 Allied Vision 相機預覽 tkinter 中的流式圖像?

[英]How can I preview streaming images in tkinter with Allied Vision camera that uses Vimba SDK?

我想使用 OpenCV 和 SDK 用於相機VimbaPython的 tkinter 框架內顯示來自 Allied Vision 相機的圖像。

初始化相機的唯一可能方法是with Python 語句:

with Vimba.get_instance() as vimba:
    cams = vimba.get_all_cameras()
    with cams[0] as camera:
        camera.get_frame()
        # Convert frame to opencv image, then use Image.fromarray and ImageTk.PhotoImage to
        # display it on the tkinter GUI

到目前為止一切正常。 但我不僅需要一個框架。 相反,我需要不斷地獲取幀並將它們顯示在屏幕上,以便流式傳輸。 我發現一種方法是從 tkinter Label 小部件調用 .after .after(delay, function)方法。 所以,得到一幀后,我想調用同樣的function來得到一個新的幀,再次顯示。 代碼如下所示:

with Vimba.get_instance() as vimba:
    cams = vimba.get_all_cameras()
    with cams[0] as camera:

        def show_frame():
            frame = camera.get_frame()
            frame = frame.as_opencv_image()
            im = Image.fromarray(frame)
            img = Image.PhotoImage(im)
            lblVideo.configure(image=img)   # this is the Tkinter Label Widget
            lblVideo.image = img

        show_frame()
        lblVideo.after(20, show_frame)

然后它顯示第一幀並停止,拋出一個錯誤,說 Vimba 需要用with語句初始化。 我對 Python 不太了解,但看起來當我使用 .after .after()方法調用 function 時,它結束了 with 語句。

我想知道是否可以在不結束with的情況下執行這個show_frame() function 。 此外,我無法每次都初始化相機,因為程序運行速度非常慢。 謝謝

我試圖讀取 openCV 中的幀並將它們顯示在 tkinter label 中。 我可以使用以下代碼來做到這一點:

import tkinter as tk
import cv2
from PIL import ImageTk, Image

video_path = "SAMPLE/STORED_VIDEO/PATH"

root = tk.Tk()
base_img = Image.open("PATH/TO/DEFAULT/LABLE/IMAGE")
img_obj = ImageTk.PhotoImage(base_img)
lblVideo = tk.Label(root, image=img_obj)
lblVideo.pack()
cap = cv2.VideoCapture(video_path)

if cap.isOpened():
    def show_frame():
        _, frame = cap.read()
        im = Image.fromarray(frame)
        img = ImageTk.PhotoImage(im)
        lblVideo.configure(image=img)
        lblVideo.image = img
        lblVideo.after(1, show_frame)  # Need to create callback here   
    show_frame()
root.mainloop()

雖然這不包含 with 語句,但您可以嘗試替換show_frame function 本身內部的after()回調。

您需要使用線程來運行捕獲代碼並傳遞通過queue讀取的幀。 然后主tkinter應用程序讀取queue並使用.after()定期顯示幀。

以下是基於您發布的代碼的示例:

import threading
from queue import SimpleQueue
import tkinter as tk
from PIL import Image, ImageTk
from vimba import Vimba

def camera_streaming(queue):
    global is_streaming
    is_streaming = True
    print("streaming started")
    with Vimba.get_instance() as vimba:
        with vimba.get_all_cameras()[0] as camera:
            while is_streaming:
                frame = camera.get_frame()
                frame = frame.as_opencv_image()
                im = Image.fromarray(frame)
                img = ImageTk.PhotoImage(im)
                queue.put(img) # put the capture image into queue
    print("streaming stopped")

def start_streaming():
    start_btn["state"] = "disabled" # disable start button to avoid running the threaded task more than once
    stop_btn["state"] = "normal"    # enable stop button to allow user to stop the threaded task
    show_streaming()
    threading.Thread(target=camera_streaming, args=(queue,), daemon=True).start()

def stop_streaming():
    global is_streaming, after_id
    is_streaming = False  # terminate the streaming thread
    if after_id:
        lblVideo.after_cancel(after_id) # cancel the showing task
        after_id = None
    stop_btn["state"] = "disabled" # disable stop button
    start_btn["state"] = "normal"  # enable start button

# periodical task to show frames in queue
def show_streaming():
    global after_id
    if not queue.empty():
        image = queue.get()
        lblVideo.config(image=image)
        lblVideo.image = image
    after_id = lblVideo.after(20, show_streaming)

queue = SimpleQueue() # queue for video frames
after_id = None

root = tk.Tk()

lblVideo = tk.Label(root, image=tk.PhotoImage(), width=640, height=480)
lblVideo.grid(row=0, column=0, columnspan=2)

start_btn = tk.Button(root, text="Start", width=10, command=start_streaming)
start_btn.grid(row=1, column=0)

stop_btn = tk.Button(root, text="Stop", width=10, command=stop_streaming, state="disabled")
stop_btn.grid(row=1, column=1)

root.mainloop()

請注意,我沒有安裝相機和 SDK,上面的代碼可能不適合你。 我只是演示如何使用線程、隊列和.after()

下面是一個測試vimba模塊(保存為vimba.py ),我使用OpenCV和網絡攝像頭來模擬VimbaPython模塊:

import cv2

class Frame:
    def __init__(self, frame):
        self.frame = frame

    def as_opencv_image(self):
        return self.frame

class Camera:
    def __init__(self, cam_id=0):
        self.cap = cv2.VideoCapture(cam_id, cv2.CAP_DSHOW)

    def __enter__(self):
        return self
    
    def __exit__(self, *args):
        self.cap.release()
        return self

    def get_frame(self):
        ret, frame = self.cap.read()
        if ret:
            return Frame(frame)

class Vimba:
    _instance = None
    
    @classmethod
    def get_instance(self):
        if self._instance is None:
            self._instance = Vimba()
        return self._instance

    def __enter__(self):
        return self

    def __exit__(self, *args):
        return self

    def get_all_cameras(self):
        return (Camera(),)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM