Is it possible to create transparent canvas in tkinter on opencv videos? OI want to draw some things on video in tkinter app.
I was trying with this code:
#Graphics window
mainWindow = tk.Tk()
mainWindow.configure(bg=lightBlue2)
mainWindow.geometry('%dx%d+%d+%d' % (maxWidth,maxHeight,0,0))
mainWindow.resizable(0,0)
# mainWindow.overrideredirect(1)
c = Canvas(mainWindow, width=640, height=480, bd=0, highlightthickness=0)
c.create_line(0,240,640,240, fill='blue')
c.pack()
mainFrame = Frame(mainWindow)
mainFrame.place(x=20, y=20)
#Capture video frames
lmain = tk.Label(mainFrame)
lmain.grid(row=0, column=0)
cap = cv2.VideoCapture('foot.mp4')
def show_frame():
ret, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image).resize((760, 400))
imgtk = ImageTk.PhotoImage(image = img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, show_frame)
closeButton = Button(mainWindow, text = "CLOSE", font = fontButtons, bg = white, width = 20, height= 1)
closeButton.configure(command= lambda: mainWindow.destroy())
closeButton.place(x=270,y=430)
show_frame() #Display
mainWindow.mainloop() #Starts GUI
but the canvas is always on bottom on video or at top of it
It isn't possible in tkinter to make a canvas transparent but it is possible to make youre winodw transparent. You need to do something else
Related
Disclaimer: I am only marginally experienced in cv2 and Tkinter , so pardon me if this question is silly.
What am I trying to do?
I am trying to read input from 2 cameras at the same time and display the resulting frames using a Tkinter GUI in real-time.
What is the issue I am facing?
There is a significant lag in the dual video streams when displayed using tkinter.
What have I tried?
I have checked if this issue persists when displaying a single video frame and the issue does not persist.
code :
import numpy as np
import cv2
import tkinter as tk
from PIL import Image, ImageTk
def show_frame_left():
_, frame = cap_left.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain_left.imgtk = imgtk
lmain_left.configure(image=imgtk)
lmain_left.after(10, show_frame_left) #previously 10
def show_frame_right():
_, frame = cap_right.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain_right.imgtk = imgtk
lmain_right.configure(image=imgtk)
lmain_right.after(5, show_frame_right) #previously 10
#Set up GUI
window = tk.Tk() #Makes main window
window.bind('<Escape>', lambda e: root.quit())
window.wm_title("Cleron Vsoft")
#Graphics window
image_frame_left = tk.Frame(window, width=600, height=500)
image_frame_left.grid(row=0, column=0, padx=10, pady=2)
#Capture video frames
lmain_left = tk.Label(image_frame_left)
lmain_left.grid(row=0, column=0)
cap_left = cv2.VideoCapture(4) #1(side cam) , 3(top cam),4(int top cam) works
#Slider window (slider controls stage position)
sliderFrame_left = tk.Frame(window, width=600, height=100)
sliderFrame_left.grid(row = 600, column=0, padx=10, pady=2)
show_frame_left() #Display 2
#Graphics window
image_frame_right = tk.Frame(window, width=600, height=500)
image_frame_right.grid(row=0, column=1, padx=10, pady=2)
#Capture video frames
lmain_right = tk.Label(image_frame_right)
lmain_right.grid(row=0, column=0)
cap_right = cv2.VideoCapture(3) #1(side cam) , 3(top cam),4(int top cam) works
#Slider window (slider controls stage position)
sliderFrame_right = tk.Frame(window, width=600, height=100)
sliderFrame_right.grid(row = 600, column=0, padx=10, pady=2)
show_frame_right() #Display 2
window.mainloop() #Starts GUI
error :
youtube link: https://youtu.be/mRVVyHfkXBc
How do I display my dual video feed without lag?
I am trying to display the screen recorder video in Tkinter. I was able to display webcam video but I am facing a problem while trying to displaying screen recorder video.
root = Tk()
# Create a frame
app = Frame(root, bg="white")
app.grid()
# Create a label in the frame
lmain = Label(app)
lmain.grid()
# Capture from camera
cap = cv2.VideoCapture(0)
def video_stream():
_, frame = cap.read()
print(frame)
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(1, video_stream)
root.after(1, video_stream)
root.mainloop()
Code used for displaying webcam video on Tkinter.
i want to display the output of opencv in this label.
but in this i want to start recording with the click of a start button and stop with stop button and if possible i want to lauch my webcam (previously coded) with the click of start webcam button simentenusly.
import datetime
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk, ImageGrab
import cv2
import numpy as np
import threading
import win32api
from tkinter.filedialog import asksaveasfilename
VIDEO_SIZE = (960, 540)
cap = cv2.VideoCapture(0)
date = datetime.datetime.now()
#filename='E:/project/videos/rec_%s%s%s%s%s%s.avi' % (date.year, date.month, date.day,
#date.hour, date.minute, date.second)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
frame_rate = 12
out = cv2.VideoWriter()
def change_r():
if rec_btn['text'] == 'Start Recording':
start_recording()
rec_btn.config(text="Stop Recoding")
else:
stop_recording()
rec_btn.config(text="Start Recording")
def change_w():
if cap_btn['text'] == 'Open webcam':
start_webcam()
cap_btn.config(text="Close Webcam")
else:
stop_webcam(event)
cap_btn.config(text="Open webcam")
# --- screen capture
def Cursor_pos(img,center,radius,color,thickness):
center = tuple(map(int,center))
rgb = [255*c for c in color[:3]] # convert to 0-255 scale for OpenCV
alpha = color[-1]
radius = int(radius)
if thickness > 0:
pad = radius + 2 + thickness
else:
pad = radius + 3
roi = slice(center[1]-pad,center[1]+pad),slice(center[0]-pad,center[0]+pad)
try:
overlay = img[roi].copy()
cv2.circle(img,center,radius,rgb, thickness=thickness, lineType=cv2.LINE_AA)
opacity = alpha
cv2.addWeighted(src1=img[roi], alpha=opacity, src2=overlay, beta=1. - opacity, gamma=0, dst=img[roi])
except:
logger.debug("transparent_circle would have been partially outside of img. Did not draw it.")
def recording_screen():
global recording
recording = True
while recording:
img = ImageGrab.grab()
frame = np.array(img)
_xs,_ys = win32api.GetCursorPos()
#curpos = root.winfo_pointerx(), root.winfo_pointery()
Cursor_pos(frame,(_xs,_ys),20,(255,255,0,0.5), -1)
#cv2.circle(frame, curpos, 10, (0,255,255), 2)
frame = cv2.resize(frame, VIDEO_SIZE)
tkimage.paste(Image.fromarray(frame))
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
out.write(frame)
def start_recording():
if not out.isOpened():
filename = asksaveasfilename(initialdir = "/",title = "Save as",mode='wb',filetypes = (("Video file","*.avi"),("all files","*.*")),defaultextension=".avi")
out.open(filename, fourcc, frame_rate, VIDEO_SIZE)
threading.Thread(target=recording_screen, daemon=True).start()
def stop_recording():
global recording
recording = False
#filename = asksaveasfilename(initialdir = "/",title = "Save as",mode='wb',filetypes = (("Video file","*.avi"),("all files","*.*")),defaultextension=".avi")
# --- webcam
webcam = None
WEBCAM_SIZE = (280, 200)
def read_frame(imgbox):
if cap.isOpened():
ret, frame = cap.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = cv2.resize(frame, WEBCAM_SIZE)
image = Image.fromarray(frame)
imgbox.image.paste(image)
webcam.after(20, read_frame, imgbox)
def stop_webcam(event):
global webcam
if webcam:
webcam.destroy()
webcam = None
def start_webcam():
global webcam
if webcam is None:
webcam = tk.Toplevel()
webcam.geometry('{}x{}+5+520'.format(WEBCAM_SIZE[0], WEBCAM_SIZE[1]))
webcam.overrideredirect(1)
imgbox = tk.Label(webcam)
imgbox.pack()
imgbox.image = ImageTk.PhotoImage(image=Image.new('RGB',WEBCAM_SIZE,(0,0,0)))
imgbox.config(image=imgbox.image)
webcam.bind('<F8>', stop_webcam)
read_frame(imgbox)
# --- main
root = tk.Tk()
tkimage = ImageTk.PhotoImage(Image.new('RGB', VIDEO_SIZE, (0,0,0)))
w, h = VIDEO_SIZE
vbox = tk.Label(root, image=tkimage, width=w, height=h, bg='black')
vbox.pack()
frame = tk.Frame(root)
frame.pack()
rec_btn = ttk.Button(frame, text='Start Recording', width=20, command=change_r)
rec_btn.grid(row=0, column=0, padx=10, pady=10)
#stop_btn = ttk.Button(frame, text='stop recording', width=20, command=stop_recording, state='disabled')
#stop_btn.grid(row=0, column=1, padx=10, pady=10)
cap_btn = ttk.Button(frame, text='Open webcam', width=20, command=change_w)
cap_btn.grid(row=0, column=2, padx=10, pady=10)
root.mainloop()
out.release()
cap.release()
i want to display my recording like this label of gui by tkinter
new and updated it is displaying two different frames one with BGR and one with RGB (how to solve this)
updated image
This is an tkinter example to capture screen to external video file:
import datetime
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk, ImageGrab
import cv2
import numpy as np
import threading
VIDEO_SIZE = (960, 540)
cap = cv2.VideoCapture(0)
date = datetime.datetime.now()
filename='E:/project/videos/rec_%s%s%s%s%s%s.avi' % (date.year, date.month, date.day,
date.hour, date.minute, date.second)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
frame_rate = 12
out = cv2.VideoWriter()
# --- screen capture
def recording_screen():
global recording
recording = True
while recording:
img = ImageGrab.grab()
frame = np.array(img)
curpos = root.winfo_pointerx(), root.winfo_pointery()
cv2.circle(frame, curpos, 10, (0,255,255), 2)
frame = cv2.resize(frame, VIDEO_SIZE)
tkimage.paste(Image.fromarray(frame))
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
out.write(frame)
def start_recording():
rec_btn.config(state='disabled')
stop_btn.config(state='normal')
if not out.isOpened():
out.open(filename, fourcc, frame_rate, VIDEO_SIZE)
threading.Thread(target=recording_screen, daemon=True).start()
def stop_recording():
global recording
recording = False
rec_btn.config(state='normal')
stop_btn.config(state='disabled')
# --- webcam
webcam = None
WEBCAM_SIZE = (280, 200)
def read_frame(imgbox):
if cap.isOpened():
ret, frame = cap.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = cv2.resize(frame, WEBCAM_SIZE)
image = Image.fromarray(frame)
imgbox.image.paste(image)
webcam.after(20, read_frame, imgbox)
def stop_webcam(event):
global webcam
if webcam:
webcam.destroy()
webcam = None
def start_webcam():
global webcam
if webcam is None:
webcam = tk.Toplevel()
webcam.geometry('{}x{}+5+520'.format(WEBCAM_SIZE[0], WEBCAM_SIZE[1]))
webcam.overrideredirect(1)
imgbox = tk.Label(webcam)
imgbox.pack()
imgbox.image = ImageTk.PhotoImage(image=Image.new('RGB',WEBCAM_SIZE,(0,0,0)))
imgbox.config(image=imgbox.image)
webcam.bind('q', stop_webcam)
read_frame(imgbox)
# --- main
root = tk.Tk()
tkimage = ImageTk.PhotoImage(Image.new('RGB', VIDEO_SIZE, (0,0,0)))
w, h = VIDEO_SIZE
vbox = tk.Label(root, image=tkimage, width=w, height=h, bg='black')
vbox.pack()
frame = tk.Frame(root)
frame.pack()
rec_btn = ttk.Button(frame, text='start recording', width=20, command=start_recording)
rec_btn.grid(row=0, column=0, padx=10, pady=10)
stop_btn = ttk.Button(frame, text='stop recording', width=20, command=stop_recording, state='disabled')
stop_btn.grid(row=0, column=1, padx=10, pady=10)
cap_btn = ttk.Button(frame, text='start webcam', width=20, command=start_webcam)
cap_btn.grid(row=0, column=2, padx=10, pady=10)
root.mainloop()
out.release()
cap.release()
Also I have used ImageGrab.grab() to take screen shot, and winfo_pointerx() and winfo_pointery() to get the mouse current position because I have not installed pywin32 and pyautogui modules.
I've created a class Tela which is basically is my Screen and I'm trying to display the webcam video on a Tkinter GUI. My webcam LED is on but the label "painel" where I want do show my video is grey. Can someone tell me what's wrong with my code. I appreciate.
class Tela:
def __init__(self, janela):
self.janela = janela
self.janela.title("Reconhecimento Facial")
self.janela.config(background="#FFFFFF")
# Open camera
self.cam = cv2.VideoCapture(0)
self.detector = dlib.get_frontal_face_detector()
self.quadro = tkinter.Frame(janela, width=600, height=500)
self.quadro.grid(row=0, column=0, padx=10, pady=2, rowspan=3)
self.painel = tkinter.Label(self.quadro)
self.quadro.grid(row=0, column=0, rowspan=3)
# Methods for screen update
self.delay = 15
self.update()
self.janela.mainloop()
def update(self):
# Get frame
ret, frame = self.cam.read()
faces, confianca, idx = self.detector.run(frame)
for i, face in enumerate(faces):
e, t, d, b = (int(face.left()), int(face.top()), int(face.right()), int(face.bottom()))
cv2.rectangle(frame, (e, t), (d, b), (0, 255, 255), 2)
cv2image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGBA)
image = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=image)
self.painel.imgtk = imgtk
self.painel.configure(image=imgtk)
self.janela.after(self.delay, self.update)
# Creates the window
Tela(tkinter.Tk())
Mistake is in second line
self.painel = tkinter.Label(self.quadro)
self.quadro.grid(row=0, column=0, rowspan=3)
You created Label but you don't put it in window - it has to be self.painel.grid instead of self.quadro.grid
self.painel = tkinter.Label(self.quadro)
self.painel.grid(row=0, column=0, rowspan=3)
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 organize where everything goes.
The following code, modified from Show webcam sequence TkInter, works fine on my Raspberry Pi:
import Tkinter as tk
import cv2
from PIL import Image, ImageTk
width, height = 800, 600
cap = cv2.VideoCapture(0)
root = tk.Tk()
lmain = tk.Label(root)
lmain.pack()
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)
show_frame()
root.mainloop()
However, combining it with Tkinter doesn't work. (In what follows, I've tried commenting out Display 1, Display 2, and neither.)
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)
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)
tk.Label(imageFrame, image=show_frame()).grid(row=0, column=0, padx=10, pady=2) #Display 1
#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
How can I get the video to display in imageFrame?
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
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()