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()
