i want to create a simple UI for screenrecording
. In my UI i have two buttons "Start Screen Recording" and "Stop Screen Recording". I can start the screen recording but when i click the stop button the recording is not stopped and i'm getting the following output:
Screenrecorder.stop_recording() missing 1 required positional argument: 'out'
This is my class Screenrecorder:
import cv2
import numpy as np
import pyautogui
class Screenrecorder():
def start_recording():
# display screen resolution, get it using pyautogui itself
SCREEN_SIZE = tuple(pyautogui.size())
# define the codec
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# frames per second
fps = 12.0
# create the video write object
out = cv2.VideoWriter("output.avi", fourcc, fps, (SCREEN_SIZE))
status = True
while status:
# make a screenshot
img = pyautogui.screenshot()
# convert these pixels to a proper numpy array to work with OpenCV
frame = np.array(img)
# convert colors from BGR to RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# write the frame
out.write(frame)
return out
def stop_recording(out):
# make sure everything is closed when exitedq
cv2.destroyAllWindows()
out.release()
Shouldn't my function "stop_recording" receive the "return out"? What am i doing wrong here? I've read that using return is one solution to pass variables to other functions and i dont want to use global variables.
The UI code:
# ScreenRecorder
# from PyscreenrecClass import MyScreenRecorder
from CV2Class import ScreenRecorder
# import pyscreenrec
# Screenshot
from ScreenshotClass import Screenshot
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Recorder")
root.geometry("400x900")
mainframe = ttk.Frame(root)
root.iconbitmap("icon.ico")
tabControl = ttk.Notebook(root)
tab1 = ttk.Frame(tabControl)
tab2 = ttk.Frame(tabControl)
tabControl.add(tab1, text ='Screen Recording')
tabControl.add(tab2, text ='Settings')
tabControl.pack(expand = 1, fill ="both")
sr = ScreenRecorder() # Right place?
Button(tab1, text="Activate Screenshot Mode", command=Screenshot.TakeScreenshot).pack()
Button(tab1, text="Start Screen Recording", command=sr.start_recording()).pack()
Button(tab1, text="Stop Screen Recording", command=sr.stop_recording()).pack()
root.mainloop()
Since you have already tried an OOP approach, I have taken the liberty of improving it a little so that you do not have to pass out
, but this is an instance variable (and thus accessible via self
):
import cv2
import numpy as np
import pyautogui
class ScreenRecorder:
def __init__(self):
self.out = None # initialize out as instance variable
def start_recording(self):
# display screen resolution, get it using pyautogui itself
SCREEN_SIZE = tuple(pyautogui.size())
# define the codec
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# frames per second
fps = 12.0
# assign the video write object to the instance variable
self.out = cv2.VideoWriter("output.avi", fourcc, fps, (SCREEN_SIZE))
status = True
while status:
# make a screenshot
img = pyautogui.screenshot()
# convert these pixels to a proper numpy array to work with OpenCV
frame = np.array(img)
# convert colors from BGR to RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# write the frame
self.out.write(frame)
def stop_recording(self):
# make sure everything is closed when exited
cv2.destroyAllWindows()
self.out.release() # access instance variable
self.out = None # reset instance variable to None
PS:
A retrun
value is returned when the function is called, but must then also be "caught" (out = Screenrecorder.start_recording()
). Without such an assignment, the return
value is not used in another function. It would be possible, for example: Screenrecorder.stop_recording(Screenrecorder.start_recording())
to pass out
directly to stop_recording
. However, this obviously makes no sense as a button function, especially because then out
is not the same object as the retrun value from pressing the start button. Rather, the first recording would continue to run and a new recording would be started and stopped immediately when stop is pressed.
EDIT
I changed the ode a little bit to work with tkinter as GUI. It is important to notice, that the tkinter mainloop()
must be in the main thread and the GUI wont be responding if you call a funtion with a endless loop itself (while True
in your recording function). Instead I outsourced the recording loop to a simple thread:
import cv2
import numpy as np
import pyautogui
from tkinter import Tk, ttk, Button
from _thread import start_new_thread
class ScreenRecorder:
def __init__(self):
self.out = None # initialize out as instance variable
self.status = False
def start_recording(self):
# display screen resolution, get it using pyautogui itself
SCREEN_SIZE = tuple(pyautogui.size())
# define the codec
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# frames per second
fps = 12.0
# assign the video write object to the instance variable
self.out = cv2.VideoWriter("output.avi", fourcc, fps, (SCREEN_SIZE))
# set status to True
self.status = True
# start record loop in new thread
start_new_thread(self._record_loop, tuple())
def _record_loop(self):
while self.status:
# make a screenshot
img = pyautogui.screenshot()
# convert these pixels to a proper numpy array to work with OpenCV
frame = np.array(img)
# convert colors from BGR to RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# write the frame if out still exists
if self.out is not None:
self.out.write(frame)
def stop_recording(self):
if self.status: # make it only stop if a recording is going on
# set status to False again
self.status = False
# make sure everything is closed when exited
cv2.destroyAllWindows()
self.out.release() # access instance variable
self.out = None # reset instance variable to None
class GUI(Tk):
def __init__(self):
super().__init__()
self.title("Recorder")
self.geometry("400x900")
mainframe = ttk.Frame(self)
#self.iconbitmap("icon.ico")
tabControl = ttk.Notebook(self)
tab1 = ttk.Frame(tabControl)
tab2 = ttk.Frame(tabControl)
tabControl.add(tab1, text='Screen Recording')
tabControl.add(tab2, text='Settings')
tabControl.pack(expand=1, fill="both")
sr = ScreenRecorder()
#Button(tab1, text="Activate Screenshot Mode", command=Screenshot.TakeScreenshot).pack()
Button(tab1, text="Start Screen Recording", command=sr.start_recording).pack()
Button(tab1, text="Stop Screen Recording", command=sr.stop_recording).pack()
if __name__ == '__main__':
ui = GUI()
ui.mainloop()