Using OpenCV with Tkinter

前端 未结 2 920
既然无缘
既然无缘 2020-11-29 03:18

I\'m writing a program that needs to display a video stream in a Tkinter window. Since there will also be buttons for performing various functions, I\'m using grid to organi

相关标签:
2条回答
  • 2020-11-29 03:38

    Try this code:

    from PIL import Image, ImageTk
    import Tkinter as tk
    import argparse
    import datetime
    import cv2
    import os
    
    class Application:
        def __init__(self, output_path = "./"):
            """ Initialize application which uses OpenCV + Tkinter. It displays
                a video stream in a Tkinter window and stores current snapshot on disk """
            self.vs = cv2.VideoCapture(0) # capture video frames, 0 is your default video camera
            self.output_path = output_path  # store output path
            self.current_image = None  # current image from the camera
    
            self.root = tk.Tk()  # initialize root window
            self.root.title("PyImageSearch PhotoBooth")  # set window title
            # self.destructor function gets fired when the window is closed
            self.root.protocol('WM_DELETE_WINDOW', self.destructor)
    
            self.panel = tk.Label(self.root)  # initialize image panel
            self.panel.pack(padx=10, pady=10)
    
            # create a button, that when pressed, will take the current frame and save it to file
            btn = tk.Button(self.root, text="Snapshot!", command=self.take_snapshot)
            btn.pack(fill="both", expand=True, padx=10, pady=10)
    
            # start a self.video_loop that constantly pools the video sensor
            # for the most recently read frame
            self.video_loop()
    
        def video_loop(self):
            """ Get frame from the video stream and show it in Tkinter """
            ok, frame = self.vs.read()  # read frame from video stream
            if ok:  # frame captured without any errors
                cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)  # convert colors from BGR to RGBA
                self.current_image = Image.fromarray(cv2image)  # convert image for PIL
                imgtk = ImageTk.PhotoImage(image=self.current_image)  # convert image for tkinter
                self.panel.imgtk = imgtk  # anchor imgtk so it does not be deleted by garbage-collector
                self.panel.config(image=imgtk)  # show the image
            self.root.after(30, self.video_loop)  # call the same function after 30 milliseconds
    
        def take_snapshot(self):
            """ Take snapshot and save it to the file """
            ts = datetime.datetime.now() # grab the current timestamp
            filename = "{}.jpg".format(ts.strftime("%Y-%m-%d_%H-%M-%S"))  # construct filename
            p = os.path.join(self.output_path, filename)  # construct output path
            self.current_image.save(p, "JPEG")  # save image as jpeg file
            print("[INFO] saved {}".format(filename))
    
        def destructor(self):
            """ Destroy the root object and release all resources """
            print("[INFO] closing...")
            self.root.destroy()
            self.vs.release()  # release web 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()
    
    0 讨论(0)
  • 2020-11-29 03:46

    This should work:

    import numpy as np
    import cv2
    import Tkinter as tk
    import Image, ImageTk
    
    #Set up GUI
    window = tk.Tk()  #Makes main window
    window.wm_title("Digital Microscope")
    window.config(background="#FFFFFF")
    
    #Graphics window
    imageFrame = tk.Frame(window, width=600, height=500)
    imageFrame.grid(row=0, column=0, padx=10, pady=2)
    
    #Capture video frames
    lmain = tk.Label(imageFrame)
    lmain.grid(row=0, column=0)
    cap = cv2.VideoCapture(0)
    def show_frame():
        _, frame = cap.read()
        frame = cv2.flip(frame, 1)
        cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
        img = Image.fromarray(cv2image)
        imgtk = ImageTk.PhotoImage(image=img)
        lmain.imgtk = imgtk
        lmain.configure(image=imgtk)
        lmain.after(10, show_frame) 
    
    
    
    #Slider window (slider controls stage position)
    sliderFrame = tk.Frame(window, width=600, height=100)
    sliderFrame.grid(row = 600, column=0, padx=10, pady=2)
    
    
    show_frame()  #Display 2
    window.mainloop()  #Starts GUI
    

    First of all, you have the line tk.Label(imageFrame, image=show_frame()).grid(row=0, column=0, padx=10, pady=2), and since show_frame() doesn't return anything, you've set image to None. Second of all, you need to make sure you lmain.grid(), otherwise lmain won't show.

    If you want to have two displays one on top of the other, you could do something like this:

    import numpy as np
    import cv2
    import Tkinter as tk
    import Image, ImageTk
    
    #Set up GUI
    window = tk.Tk()  #Makes main window
    window.wm_title("Digital Microscope")
    window.config(background="#FFFFFF")
    
    #Graphics window
    imageFrame = tk.Frame(window, width=600, height=500)
    imageFrame.grid(row=0, column=0, padx=10, pady=2)
    
    #Capture video frames
    
    cap = cv2.VideoCapture(0)
    
    def show_frame():
        _, frame = cap.read()
        frame = cv2.flip(frame, 1)
        cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
        img = Image.fromarray(cv2image)
        imgtk = ImageTk.PhotoImage(image=img)
        display1.imgtk = imgtk #Shows frame for display 1
        display1.configure(image=imgtk)
        display2.imgtk = imgtk #Shows frame for display 2
        display2.configure(image=imgtk)
        window.after(10, show_frame) 
    
    display1 = tk.Label(imageFrame)
    display1.grid(row=1, column=0, padx=10, pady=2)  #Display 1
    display2 = tk.Label(imageFrame)
    display2.grid(row=0, column=0) #Display 2
    
    #Slider window (slider controls stage position)
    sliderFrame = tk.Frame(window, width=600, height=100)
    sliderFrame.grid(row = 600, column=0, padx=10, pady=2)
    
    show_frame() #Display
    window.mainloop()  #Starts GUI
    
    0 讨论(0)
提交回复
热议问题