Jul-04-2021, 08:48 PM
Hello all! I am working on an app that opens the webcam and then allows various functionality such as save image, change brightness etc.
I have implemented a drawing/annotation function so the user can freely draw with the mouse. This works except my update function keeps covering the drawing with the latest image frame from the webcam.
Any ideas on how to get the drawing to stay on top of each new frame from the update function? Thanks
I have implemented a drawing/annotation function so the user can freely draw with the mouse. This works except my update function keeps covering the drawing with the latest image frame from the webcam.
Any ideas on how to get the drawing to stay on top of each new frame from the update function? Thanks
import tkinter as tk import ImageChops, sys, pygame from pygame.locals import * import random import cv2 from PIL import Image, ImageTk, ImageEnhance import PIL import time from tkinter import filedialog import numpy as np class App: def __init__(self, video_source=0): self.overlay_img = None self.painting = None white = (255,255,255) x1, y1 = [0, 0] x2, y2 = [0, 0] self.appName = "Kamera" self.window = tk.Tk() self.window.title(self.appName) self.window.geometry("640x520+0+0") self.window.resizable(0, 0) self.window.attributes('-alpha', 0.5) self.window['bg'] = 'black' self.video_source = video_source self.vid = MyVideoCapture(self.video_source) #self.paint_frame = tk.Frame(self.window, width=self.vid.width, height=self.vid.height) #self.paint_frame.pack() #self.frame = tk.Frame(self.window, width=self.vid.width, height=self.vid.height) #self.frame.pack() self.canvas = tk.Canvas(self.window, width=self.vid.width, height=self.vid.height, bg='red') self.canvas.pack() self.canvas.bind("<B1-Motion>",self.paint) self.btn_snapshot = tk.Button(self.window, text="Snapshot", width=5, command=self.snapshot) self.btn_snapshot.pack(side=tk.LEFT, padx=10) self.btn_overlay = tk.Button(self.window, text="Overlay", width=7, command=self.overlay) self.btn_overlay.pack(side=tk.LEFT, padx=10) self.btn_settings = tk.Button(self.window, text="Settings", width=5, command=self.settings) self.btn_settings.pack(side=tk.LEFT, padx=10) self.zoom_slide_value = 1 self.slide_value = 200 self.update() self.window.mainloop() def settings(self): self.newWindow = tk.Toplevel(self.window) self.newWindow.title("Settings") self.newWindow.geometry("400x400+0+0") #self.newWindow.attributes('-transparentcolor', 'red') self.newWindow.resizable(0, 0) #Button to mirror/flip image self.btn_flip = tk.Button(self.newWindow, text="Mirror Image", width=10, command=self.flip_img) self.btn_flip.pack(side=tk.LEFT, padx=10) #Zoom Slider self.zoom = tk.Scale( self.newWindow, length=200, from_=1, to=4, orient=tk.HORIZONTAL, label='Zoom', command=self.zoomslider) self.zoom.set(0) self.zoom.pack(anchor=tk.NW) #Brightness Slider self.brightness = tk.Scale( self.newWindow, length=200, from_=0, to=255, orient=tk.HORIZONTAL, label="Image Brightness", command=self.slide) self.brightness.set(200) self.brightness.pack(anchor=tk.NW) def paint(self, event): white = (255, 255, 255) x1, y1 = (event.x - 2), (event.y - 2) x2, y2 = (event.x + 2), (event.y + 2) self.canvas.create_oval(x1, y1, x2, y2, fill="white", outline="white") def zoomslider(self, var): self.zoom_slide_value = self.zoom.get() print(self.zoom_slide_value) def slide(self, var): self.slide_value = self.brightness.get() print(self.slide_value) def flip_img(self): self.vid.flipped = not self.vid.flipped def overlay(self): file = filedialog.askopenfile( mode='rb', defaultextension='.png',title="Choose Overlay Image", filetypes=[("PNG Files", '*.png')]) if file: self.overlay_img = ImageTk.PhotoImage(file=file) def snapshot(self): isTrue, frame = self.vid.getFrame() if isTrue: filename = filedialog.asksaveasfilename( defaultextension='.jpg', title="Choose Filename", filetypes=[("JPEG Files", '*.jpg')]) # image = "IMG-" + time.strftime("%H-%M-%S-%d-%m") + ".jpg" cv2.imwrite(filename, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # msg = Label(self.window, text='Image Saved' + image, bg='black', fg='green').place(x=430, y=510) else: messagebox.showerror("paint says", "unable to save image ,\n something went wrong") def update(self): isTrue, frame = self.vid.getFrame() #Control frame brightness frame = cv2.normalize(frame, frame, 0, self.slide_value, cv2.NORM_MINMAX) #Control frame size width = int(self.vid.width * self.zoom_slide_value) height = int(self.vid.height * self.zoom_slide_value) dsize = (width, height) frame = cv2.resize(frame, dsize, interpolation = cv2.INTER_AREA) #Convert frame to TK and put on canvas if isTrue: self.photo = ImageTk.PhotoImage(image=PIL.Image.fromarray(frame)) self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW) #Display overlay if self.overlay_img: self.canvas.create_image(0,0, image=self.overlay_img, anchor=tk.NW) self.window.after(10, self.update) class MyVideoCapture: def __init__(self, video_source=0): self.vid = cv2.VideoCapture(video_source) if not self.vid.isOpened(): raise ValueError("Unable to open this camera \n select another video source", video_source) self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH) self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT) self.flipped = True def getFrame(self): if self.vid.isOpened(): isTrue, frame = self.vid.read() if isTrue and self.flipped: frame = cv2.flip(frame, 1) if isTrue: return (isTrue, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) else: return (isTrue, None) else: return (isTrue, None) def __del__(self): if self.vid.isOpened(): self.vid.release() if __name__ == "__main__": App()