basler / pypylon

The official python wrapper for the pylon Camera Software Suite
http://www.baslerweb.com
BSD 3-Clause "New" or "Revised" License
559 stars 207 forks source link

How to capture a video and displayed it in a GUI developed with Tkinter using pypylon #72

Closed zamar1022 closed 5 months ago

zamar1022 commented 5 years ago

The idea is to develop a simple GUI with Tkinter. After that take a video and display it in the GUI. I have been able to display a video using openCV, but now I want to show it in a GUI. Can anybody help me? Thanks

PolymaTh-EE98 commented 5 years ago

https://solarianprogrammer.com/2018/04/21/python-opencv-show-video-tkinter-window/

zamar1022 commented 5 years ago

Thanks for the answer, but the idea is to take the video with pypylon (using basler cameras, basler dart) and without saving the video in the local disk display it in the tkinter GUI.

I saw the link that you put it, but I think that that doesn't work.

Please help me

gustavoponce7 commented 5 years ago

Hi @zamar1022 I want to achieve a similar behavior but I want to display the video in the browser, basically what I am looking is the following --> "take the video with pypylon (using basler cameras, basler dart) and without saving the video in the local disk display it in the browser"

Did you make it work? or do you have any advice?

elishatam commented 5 years ago

I have something that works after going through the solarianprogrammer.com tutorial.

It uses pypylon to capture images from a basler camera and then displays the images in a Tkinter GUI. Output is a real-time display, without having to save the video on local disk.

This is my main.py:

import tkinter as tk
from tkinter import ttk
from tkinter.constants import *
import oneCameraCapture
import PIL.Image, PIL.ImageTk
import cv2
import time

class Page(tk.Frame):

    def __init__(self, parent, window):

        tk.Frame.__init__(self, parent)
        self.window = window
        self.window.title = "Title"

        #Open camera source
        self.vid = oneCameraCapture.cameraCapture()

        #Create a canvas that will fit the camera source
        self.canvas = tk.Canvas(window, width=1000,height=600)
        self.canvas.grid(row=0, column=0)

        menuFrame = ttk.Labelframe(window, text=("Menu"))
        menuFrame.grid(row=1, column=0, sticky="NSW",
            padx=5, pady=2)

        #Button that lets the user take a snapshot
        self.btnSaveImage = tk.Button(menuFrame, text="Save Image", command=self.saveImage)
        self.btnSaveImage.grid(row=0, column=2, sticky="W")

        self.delay=100
        self.update()
        #self.window.mainloop()

    def update(self):
        #Get a frame from cameraCapture
        frame = self.vid.getFrame() #This is an array
        #https://stackoverflow.com/questions/48121916/numpy-resize-rescale-image/48121996
        frame = cv2.resize(frame, dsize=(1000, 600), interpolation=cv2.INTER_CUBIC)

        #OpenCV bindings for Python store an image in a NumPy array
        #Tkinter stores and displays images using the PhotoImage class
        # Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
        self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
        self.canvas.create_image(500,300,image=self.photo)

        self.window.after(self.delay, self.update)

    def saveImage(self):
        # Get a frame from the video source
        frame = self.vid.getFrame()

        cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg",
                    cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))

if __name__ == "__main__":
    root = tk.Tk()
    testWidget = Page(root, root) 
    testWidget.grid(row=0, column=0, sticky="W")
    root.mainloop()

This is my cameraCapture class (oneCameraCapture.py)

import os

os.environ["PYLON_CAMEMU"] = "3"

from pypylon import genicam
from pypylon import pylon
import sys
import time
import cv2
import numpy as np
import tkinter as tk

class cameraCapture(tk.Frame):
    def __init__(self):
        self.img0 = []
        self.windowName = 'title'

        try:
            # Create an instant camera object with the camera device found first.
            self.camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())

            self.camera.Open()  #Need to open camera before can use camera.ExposureTime
            self.camera.ExposureTime.SetValue(500)
            self.camera.Width=2448
            self.camera.Height=2048
            # Print the model name of the camera.
            print("Using device ", self.camera.GetDeviceInfo().GetModelName())
            print("Exposure time ", self.camera.ExposureTime.GetValue())

            # According to their default configuration, the cameras are
            # set up for free-running continuous acquisition.
            #Grabbing continuously (video) with minimal delay
            self.camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) 

            # converting to opencv bgr format
            self.converter = pylon.ImageFormatConverter()
            self.converter.OutputPixelFormat = pylon.PixelType_BGR8packed
            self.converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned

        except genicam.GenericException as e:
            # Error handling
            print("An exception occurred.", e.GetDescription())
            exitCode = 1

    def getFrame(self):
        try:
            self.grabResult = self.camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)

            if self.grabResult.GrabSucceeded():
                image = self.converter.Convert(self.grabResult) # Access the openCV image data
                self.img0 = image.GetArray()

            else:
                print("Error: ", self.grabResult.ErrorCode)

            self.grabResult.Release()
            #time.sleep(0.01)

            return self.img0

        except genicam.GenericException as e:
            # Error handling
            print("An exception occurred.", e.GetDescription())
            exitCode = 1

if __name__ == "__main__":
    testWidget = cameraCapture()
    while testWidget.camera.IsGrabbing():
        #input("Press Enter to continue...")
        testWidget.getFrame()

        #If window has been closed using the X button, close program
        # getWindowProperty() returns -1 as soon as the window is closed
        if cv2.getWindowProperty(testWidget.windowName, 0) < 0:
            cv2.destroyAllWindows()
            break
        if testWidget.k == 27: #If press ESC key
            print('ESC')
            cv2.destroyAllWindows()
            break
danielcovaci commented 4 years ago

I have something that works after going through the solarianprogrammer.com tutorial.

It uses pypylon to capture images from a basler camera and then displays the images in a Tkinter GUI. Output is a real-time display, without having to save the video on local disk.

This is my main.py:

import tkinter as tk
from tkinter import ttk
from tkinter.constants import *
import oneCameraCapture
import PIL.Image, PIL.ImageTk
import cv2
import time

class Page(tk.Frame):

    def __init__(self, parent, window):

        tk.Frame.__init__(self, parent)
        self.window = window
        self.window.title = "Title"

        #Open camera source
        self.vid = oneCameraCapture.cameraCapture()

        #Create a canvas that will fit the camera source
        self.canvas = tk.Canvas(window, width=1000,height=600)
        self.canvas.grid(row=0, column=0)

        menuFrame = ttk.Labelframe(window, text=("Menu"))
        menuFrame.grid(row=1, column=0, sticky="NSW",
            padx=5, pady=2)

        #Button that lets the user take a snapshot
        self.btnSaveImage = tk.Button(menuFrame, text="Save Image", command=self.saveImage)
        self.btnSaveImage.grid(row=0, column=2, sticky="W")

        self.delay=100
        self.update()
        #self.window.mainloop()

    def update(self):
        #Get a frame from cameraCapture
        frame = self.vid.getFrame() #This is an array
        #https://stackoverflow.com/questions/48121916/numpy-resize-rescale-image/48121996
        frame = cv2.resize(frame, dsize=(1000, 600), interpolation=cv2.INTER_CUBIC)

        #OpenCV bindings for Python store an image in a NumPy array
        #Tkinter stores and displays images using the PhotoImage class
        # Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
        self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
        self.canvas.create_image(500,300,image=self.photo)

        self.window.after(self.delay, self.update)

    def saveImage(self):
        # Get a frame from the video source
        frame = self.vid.getFrame()

        cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg",
                    cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))

if __name__ == "__main__":
    root = tk.Tk()
    testWidget = Page(root, root) 
    testWidget.grid(row=0, column=0, sticky="W")
    root.mainloop()

This is my cameraCapture class (oneCameraCapture.py)

import os

os.environ["PYLON_CAMEMU"] = "3"

from pypylon import genicam
from pypylon import pylon
import sys
import time
import cv2
import numpy as np
import tkinter as tk

class cameraCapture(tk.Frame):
    def __init__(self):
        self.img0 = []
        self.windowName = 'title'

        try:
            # Create an instant camera object with the camera device found first.
            self.camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())

            self.camera.Open()  #Need to open camera before can use camera.ExposureTime
            self.camera.ExposureTime.SetValue(500)
            self.camera.Width=2448
            self.camera.Height=2048
            # Print the model name of the camera.
            print("Using device ", self.camera.GetDeviceInfo().GetModelName())
            print("Exposure time ", self.camera.ExposureTime.GetValue())

            # According to their default configuration, the cameras are
            # set up for free-running continuous acquisition.
            #Grabbing continuously (video) with minimal delay
            self.camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) 

            # converting to opencv bgr format
            self.converter = pylon.ImageFormatConverter()
            self.converter.OutputPixelFormat = pylon.PixelType_BGR8packed
            self.converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned

        except genicam.GenericException as e:
            # Error handling
            print("An exception occurred.", e.GetDescription())
            exitCode = 1

    def getFrame(self):
        try:
            self.grabResult = self.camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)

            if self.grabResult.GrabSucceeded():
                image = self.converter.Convert(self.grabResult) # Access the openCV image data
                self.img0 = image.GetArray()

            else:
                print("Error: ", self.grabResult.ErrorCode)

            self.grabResult.Release()
            #time.sleep(0.01)

            return self.img0

        except genicam.GenericException as e:
            # Error handling
            print("An exception occurred.", e.GetDescription())
            exitCode = 1

if __name__ == "__main__":
    testWidget = cameraCapture()
    while testWidget.camera.IsGrabbing():
        #input("Press Enter to continue...")
        testWidget.getFrame()

        #If window has been closed using the X button, close program
        # getWindowProperty() returns -1 as soon as the window is closed
        if cv2.getWindowProperty(testWidget.windowName, 0) < 0:
            cv2.destroyAllWindows()
            break
        if testWidget.k == 27: #If press ESC key
            print('ESC')
            cv2.destroyAllWindows()
            break

from that tutorial i have implemented into gui designed with PAGE, my only problem is that camera feed does not fit the canvas, and the snapshot also does not have the canvas dimensions :( Screenshot_10

Screenshot_11

and here is my code `#! /usr/bin/env python

-- coding: utf-8 --

#

GUI module generated by PAGE version 5.4

in conjunction with Tcl version 8.6

Sep 04, 2020 04:46:23 PM +0200 platform: Windows NT

import sys

try: import Tkinter as tk except ImportError: import tkinter as tk

try: import ttk py3 = False except ImportError: import tkinter.ttk as ttk py3 = True

import snapshot_support

##################tutorial################ import cv2 import PIL.Image, PIL.ImageTk import time

def vp_start_gui(): '''Starting point when module is the main routine.''' global val, w, root root = tk.Tk() top = scannerApp (root) snapshot_support.init(root, top) root.mainloop()

w = None def create_scannerApp(rt, *args, *kwargs): '''Starting point when module is imported by another module. Correct form of call: 'create_scannerApp(root, args, **kwargs)' .''' global w, w_win, root

rt = root

root = rt
w = tk.Toplevel (root)
top = scannerApp (w)
snapshot_support.init(w, top, *args, **kwargs)
return (w, top)

def destroy_scannerApp(): global w w.destroy() w = None

class scannerApp: def init(self, top=None, video_source=0): '''This class configures and populates the toplevel window. top is the toplevel containing window.''' _bgcolor = '#d9d9d9' # X11 color: 'gray85' _fgcolor = '#000000' # X11 color: 'black' _compcolor = '#d9d9d9' # X11 color: 'gray85' _ana1color = '#d9d9d9' # X11 color: 'gray85' _ana2color = '#ececec' # Closest X11 color: 'gray92'

    top.geometry("600x450+420+128")
    top.minsize(120, 1)
    top.maxsize(1370, 749)
    top.resizable(1, 1)
    top.title("scaner")
    top.configure(background="#d9d9d9")

    self.video_source = video_source

    # open video source (by default this will try to open the computer webcam)
    self.vid = MyVideoCapture(self.video_source)

    # Create a canvas that can fit the above video source size

    self.Canvas1 = tk.Canvas(top) 

    self.Canvas1.place(relx=0.05, rely=0.244, relheight=0.651
            , relwidth=0.355)
    self.Canvas1.configure(background="#d9d9d9")
    self.Canvas1.configure(borderwidth="2")
    self.Canvas1.configure(insertbackground="black")
    self.Canvas1.configure(relief="ridge")
    self.Canvas1.configure(selectbackground="blue")
    self.Canvas1.configure(selectforeground="white")

    self.startFeedButton = tk.Button(top)
    self.startFeedButton.place(relx=0.05, rely=0.022, height=34, width=207)
    self.startFeedButton.configure(activebackground="#ececec")
    self.startFeedButton.configure(activeforeground="#000000")
    self.startFeedButton.configure(background="#d9d9d9")
    self.startFeedButton.configure(disabledforeground="#a3a3a3")
    self.startFeedButton.configure(foreground="#000000")
    self.startFeedButton.configure(highlightbackground="#d9d9d9")
    self.startFeedButton.configure(highlightcolor="black")
    self.startFeedButton.configure(pady="0")
    self.startFeedButton.configure(text='''start''')

    self.snapshotButton = tk.Button(top)
    self.snapshotButton.place(relx=0.05, rely=0.133, height=34, width=207)
    self.snapshotButton.configure(activebackground="#ececec")
    self.snapshotButton.configure(activeforeground="#000000")
    self.snapshotButton.configure(background="#d9d9d9")
    self.snapshotButton.configure(disabledforeground="#a3a3a3")
    self.snapshotButton.configure(foreground="#000000")
    self.snapshotButton.configure(highlightbackground="#d9d9d9")
    self.snapshotButton.configure(highlightcolor="black")
    self.snapshotButton.configure(pady="0")
    self.snapshotButton.configure(text='''snapshot''', command=self.snapshot)

    # After it is called once, the update method will be automatically called every delay milliseconds
    self.delay = 15
    self.update()

    self.Canvas1.mainloop()

def snapshot(self):
     # Get a frame from the video source
      ret, frame = self.vid.get_frame()

      if ret:
        cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))

def update(self):
     # Get a frame from the video source
      ret, frame = self.vid.get_frame()

      if ret:
         self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
         self.Canvas1.create_image(0, 0, image = self.photo, anchor = tk.NW)

      self.Canvas1.after(self.delay, self.update)

class MyVideoCapture: def init(self, video_source=0):

Open the video source

      self.vid = cv2.VideoCapture(video_source)
      if not self.vid.isOpened():
         raise ValueError("Unable to open video source", video_source)

     # Get video source width and height
      self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
      self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)

  def get_frame(self):
      if self.vid.isOpened():
         ret, frame = self.vid.read()
         if ret:
             # Return a boolean success flag and the current frame converted to BGR
              return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
         else:
              return (ret, None)
      else:
         return (ret, None)

 # Release the video source when the object is destroyed
  def __del__(self):
      if self.vid.isOpened():
         self.vid.release()

if name == 'main': vp_start_gui()

`

Ahmed-a-m commented 3 years ago

@danielcovaci : Hello, were you able to solve this problem using PAGE builder. I am trying to build a Qr scanner that will just display the Qr while scanning. wanted to display the video. what did you choose from the widget toolbar to display the video output? Thanks