how to upload video to AWS while capturing videos using openCV python - python

I have a Tkinter multiFrame/pages application In one of the frames i have camera related work i.e when I go on the page the camera automatically start and start capturing 20 sec video recording with openCV that means when video gets 20 second long it saves video locally and then starts recording new video of 20 second now i want those videos to upload on aws when a video gets recorded and got saved locally how can i achieve that whenever a video gets record i want that video should upload to aws automatically and get deleted from local computer and than this process should again start when new 20 second video is recorded.
my code
class FrontCameraPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.cameraFrame = tk.Frame(self, bg=gray)
self.cameraFrame.grid(row=1, column=0, sticky="nsew")
self.buttonFrame = tk.Frame(self, bg="white")
self.buttonFrame.grid(row=1, column=1, sticky="nsew", padx=(10, 0))
self.stop= tk.Button(self.buttonFrame, text="END TRIP", font=small_Font, bg=dark_blue, fg="White")
self.stop.grid(row=2, column=0, ipadx=10, pady=(0, 5))
self.stop['command'] = self.stop_capture
self.cancelButton = tk.Button(self.buttonFrame, text="Cancel", font=small_Font, bg=dark_blue, fg="white")
self.cancelButton.grid(row=3, column=0, ipadx=10)
self.cancelButton['command'] = lambda: controller.show_frame(go_to_some_page)
# setup callbacks for switching in and out events
self.bind('<<SwitchIn>>', self.start_capture)
self.bind('<<SwitchOut>>', self.stop_capture)
self.lmain = tk.Label(self.cameraFrame)
self.lmain.pack()
self.capture = None
def start_capture(self, event=None):
if self.capture is None:
#-----------------------------------
width, height = 200, 200
self.cap = cv2.VideoCapture(0)
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
# used instance variables for width and height
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# initialize file rotation and frame counters
self.timer = 1 # file rotation counter
self.frames = 0 # frame counter
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out = cv2.VideoWriter(
f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
#-----------------------------------
self.show_frame()
print('capture started')
def stop_capture(self, event=None):
if self.capture:
self.after_cancel(self.capture)
#-----------------------------------
self.cap.release()
self.out.release()
#------------------------------
self.capture = None
print('capture stopped')
def show_frame(self):
ret, frame = self.cap.read()
if ret:
self.out.write(frame)
self.frames += 1
if self.frames >= 500:
self.out.release()
self.timer += 1
self.out.open(f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
self.frames = 0
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
self.imgtk = ImageTk.PhotoImage(image=img)
self.lmain.configure(image=self.imgtk)
self.capture = self.after(10, self.show_frame)

Related

how to stop OpenCV video capturing/recording after sometime and start again in tkinter

I have a python application which have many frames/pages when I go to some some camera page I start the camera and after 20 second I want to close the video recording and start recording in a new file. basically splitting a the recording into 20 second videos.
now I have a function stop_20_seconds() function which stops the recording after 20 second and starts again. but right now I am getting multiple file without the 20 second break one after another.
my code
class FrontCameraPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.label = tk.Label(self, text="FRONT CAMERA", font=MediumFont, bg="white").grid(row=0, column=0, columnspan=2, sticky="nsew")
self.cameraFrame = tk.Frame(self, bg=gray)
self.cameraFrame.grid(row=1, column=0, sticky="nsew")
self.buttonFrame = tk.Frame(self, bg="white")
self.buttonFrame.grid(row=1, column=1, sticky="nsew", padx=(10, 0))
self.endTrip = tk.Button(self.buttonFrame, text="END TRIP", font=small_Font, bg=dark_blue, fg="White")
self.endTrip.grid(row=2, column=0, ipadx=10, pady=(0, 5))
self.endTrip['command'] = self.stop_capture
self.cancelButton = tk.Button(self.buttonFrame, text="Cancel", font=small_Font, bg=dark_blue, fg="white")
self.cancelButton.grid(row=3, column=0, ipadx=10)
self.cancelButton['command'] = lambda: controller.show_frame(changepage)
# setup callbacks for switching in and out events
self.bind('<<SwitchIn>>', self.start_capture)
self.bind('<<SwitchOut>>', self.stop_capture)
self.capture = None
self.lmain = tk.Label(self.cameraFrame)
self.lmain.pack()
def start_capture(self, event=None):
if self.capture is None:
#-----------------------------------
width, height = 200, 200
self.cap = cv2.VideoCapture(0)
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out = cv2.VideoWriter('output.avi', self.fourcc, 25, (width, height))
#-----------------------------------
self.timer =0
self.show_frame()
print('capture started')
def stop_capture(self, event=None):
if self.capture:
self.after_cancel(self.capture)
#-----------------------------------
self.cap.release()
self.out.release()
#------------------------------
self.capture = None
print('capture stopped')
def show_frame(self):
ret, frame = self.cap.read()
if ret:
self.out.write(frame)
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
self.imgtk = ImageTk.PhotoImage(image=img)
self.lmain.configure(image=self.imgtk)
self.stop20Sec = self.after(5000, self.stop_20_seconds)
self.capture = self.after(10, self.show_frame)
def stop_20_seconds(self):
self.timer += 1
self.out.release()
width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.out = cv2.VideoWriter(f'{str(self.timer)}.avi', self.fourcc, 25, (width, height))
self.after_cancel(self.capture)
self.after_cancel(self.stop20Sec)
self.stop20Sec = None
self.capture = None
self.show_frame()
Actually you don't need stop_20_seconds(). Just do the output file rotation inside show_frame():
def start_capture(self, event=None):
if self.capture is None:
#-----------------------------------
width, height = 200, 200
self.cap = cv2.VideoCapture(0)
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
# used instance variables for width and height
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# initialize file rotation and frame counters
self.timer = 1 # file rotation counter
self.frames = 0 # frame counter
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out = cv2.VideoWriter(f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
#-----------------------------------
self.show_frame()
print('capture started')
...
def show_frame(self):
ret, frame = self.cap.read()
if ret:
self.out.write(frame)
self.frames += 1 # update frame counter
if self.frames >= 500: # reach 20 seconds (20x25 frames)
self.out.release() # close current output file
self.timer += 1 # update file rotation counter
self.out.open(f'{self.timer}.avi', self.fourcc, 25, (self.width, self.height))
self.frames = 0 # reset frame counter
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
self.imgtk = ImageTk.PhotoImage(image=img)
self.lmain.configure(image=self.imgtk)
self.capture = self.after(10, self.show_frame)
Note: since the actual capture frame rate is not the same as the output frame rate, the actual time period in each video file may not be 20 seconds in real time.

Trouble calling a camera capture function tkinter

I am trying to create different radio buttons for different methods of uploading an image. I created a function for running a camera and showcasing it with a button to take a picture. Whenever I call this function it works. But when I try to call it inside tk.radiobutton I get the following error.
_tkinter.TclError: image "pyimage77" doesn't exist
Here is my code. I try to create a function called camerachoice which creates a window for the camera. #
import tkinter as tk
from tkinter import filedialog
import cv2
import PIL.Image, PIL.ImageTk
import time
def camerachoice():
class App:
def __init__(self, window, window_title, video_source=0):
self.window = window
self.window.title(window_title)
self.video_source = video_source
self.vid = MyVideoCapture(self.video_source)
self.canvas = tk.Canvas(window, width = self.vid.width, height = self.vid.height)
self.canvas.pack()
self.btn_snapshot=tk.Button(window, text="Snapshot", width=50, command=self.snapshot)
self.btn_snapshot.pack(anchor=tk.CENTER, expand=True)
self.delay = 15
self.update()
self.window.mainloop()
def snapshot(self):
ret, frame = self.vid.get_frame()
if ret:
#cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M- br%S") + ".jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
cv2.imwrite("cancercheck.jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
def update(self):
ret, frame = self.vid.get_frame()
if ret:
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tk.NW)
self.window.after(self.delay, 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 video source", video_source)
self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
def get_frame(self):
if self.vid.isOpened():
ret, frame = self.vid.read()
if ret:
return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
else:
return (ret, None)
else:
return (ret, None)
def __del__(self):
if self.vid.isOpened():
self.vid.release()
#App()
App(tk.Tk(), "Tkinter and OpenCV")
root = tk.Tk()
v = tk.IntVar()
tk.Label(root,
text="""Choose method:""",
justify = tk.LEFT,
padx = 20).pack()
tk.Radiobutton(root,
text="Camera",
padx = 20,
variable=v,
command=camerachoice(),
value=2,
).pack(anchor=tk.W)
root.mainloop()

How to execute two or more functions at a time without delaying GUI elements in Tkinter?

I wrote a code in Tkinter that should execute the function of face recognition as soon as the user click on the button and simultaneously it should redirect to the next frame.
What the problem I am currently facing is, when the user clicks on the button, the face recognition function, that is in my code gen(), executes first and as soon as it terminates, it redirects to the next frame.
What I want is both should work at the same time.. Any suggestion please?
from tkinter import *
from PIL import Image, ImageTk
import cv2
import numpy as np
import os
import json
class tkinterApp(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = Frame(self)
container.pack(side = "top", fill = "both", expand = True)
self.frames = {}
for F in (StartPage, Page1, Page2):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky ="nsew")
self.update()
self.show_frame(StartPage)
def show_frame(self, cont):
if cont not in self.frames:
self.frames[cont] = cont(self.container, self)
frame = self.frames[cont]
frame.tkraise()
frame.event_generate("<<ShowFrame>>")
class StartPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller = controller
self.bind("<<ShowFrame>>", self.myStartPage)
def myStartPage(self,controller):
super(StartPage).__init__()
canvas = Canvas(self,width=2300, height=900, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
self.background = PhotoImage(file="Images/background.png")
canvas.create_image(525,425,image=self.background, tags="B")
self.bg = PhotoImage(file="Images/bg-top.png")
canvas.create_image(0,335,image=self.bg, anchor=NW)
self.my_pic1 = PhotoImage(file="Images/start000-befored.png")
obj1 = canvas.create_image(1200,290,image=self.my_pic1, anchor=NW)
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
cascadePath = "Cascades/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)
font = cv2.FONT_HERSHEY_SIMPLEX
cam = cv2.VideoCapture(0)
cam.set(3, 640)
cam.set(4, 480)
minW = 0.1*cam.get(3)
minH = 0.1*cam.get(4)
def get_frame():
laebl = ""
names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W']
while True:
ret, img =cam.read()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor = 1.2,
minNeighbors = 5,
minSize = (int(minW), int(minH)),
)
for(x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
label, confidence = recognizer.predict(gray[y:y+h,x:x+w])
if (confidence < 50):
label = names[label]
confidence = " {0}%".format(round(100 - confidence))
else:
label = "unknown"
confidence = " {0}%".format(round(100 - confidence))
cv2.putText(img, str(label), (x+5,y-5), font, 1, (255,255,255), 2)
cv2.putText(img, str(confidence), (x+5,y+h-5), font, 1, (255,255,0), 1)
#cv2.imshow('camera',img)
ret, jpeg = cv2.imencode('.jpg', img)
cv2.destroyAllWindows()
return label, jpeg.tobytes()
def gen():
flag = 1
while True:
label, frame = get_frame()
flag += 1
if label=="unknown" and flag > 70:
cam.release()
print("Unknown Face Detected!")
break
canvas.tag_bind(obj1, '<1>', lambda event=None : [self.controller.show_frame(Page1), gen()])
class Page1(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller = controller
self.bind("<<ShowFrame>>", self.myPage1)
def myPage1(self,controller):
super(Page1).__init__()
canvas = Canvas(self,width=2300, height=900, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
self.background = PhotoImage(file="Images/background.png")
canvas.create_image(525,425,image=self.background, tags="B")
self.bg = PhotoImage(file="Images/bg-top.png")
bg_tk = canvas.create_image(0,335,image=self.bg, anchor=NW)
self.bg1 = PhotoImage(file="Images/bg-bottom.png")
bg1_tk = canvas.create_image(0,335,image=self.bg1, anchor=NW)
self.after(3000, lambda event=None : self.controller.show_frame(Page2))
class Page2(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller = controller
self.bind("<<ShowFrame>>", self.myPage2)
def myPage2(self,controller):
super(Page1).__init__()
canvas = Canvas(self,width=2300, height=900, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
self.background = PhotoImage(file="Images/background.png")
canvas.create_image(525,425,image=self.background)
self.bg = PhotoImage(file="Images/bg-top.png")
bg_tk = canvas.create_image(0,70,image=self.bg, anchor=NW)
self.bg1 = PhotoImage(file="Images/bg-bottom.png")
bg1_tk = canvas.create_image(0,777,image=self.bg1, anchor=NW)
# Driver Code
app = tkinterApp()
app.title("My Project")
app.mainloop()

How to make child Tkinter object trigger a change in parent's widget

Edit: thanks to #jasonharper's comments below I can ask a more informed question:
I have a main app, and a separate module snipping_tool.py that handles creating a new window with the option to screen-snip or select an image file. I want snipping_tool.py to provide an image to the main app, but currently I'm trying to retrieve the image too soon (before the snipping_tool window even opens).
How can I wait until the user selects or grabs an image before I try to assign MyNewObject.selected_image? Should I use a binding or some event handler? (I have limited experience with both). Or is there a simpler way?
Simplified Main App:
import tkinter as tk
import snipping_tool
class MinCodeEx:
def __init__(self, master):
self.master = master
self.ButtonA = tk.Button(width=60,height=40,command = lambda: self.UpdateImg(master))
self.ButtonA.pack()
def UpdateImg(self, master):
newDialog = snipping_tool.AcquireImage(self.master)
# self.ButtonA['image'] = newDialog.image_selected
#if newDialog.image_selected:
self.ButtonA.config(image=newDialog.image_selected)
print(newDialog.image_selected)
def main():
root = tk.Tk()
MinCodeEx(root)
root.mainloop()
if __name__ == '__main__':
main()
snipping_tool.py
returns None instead of an image file since I'm trying to retrieve the selected_image too soon.
import tkinter as tk
from PIL import ImageGrab, ImageTk, Image
import cv2
import numpy as np
from tkinter import filedialog
class ScreenSnip(tk.Toplevel):
def __init__(self, master):
super().__init__(master)
self.image = None
def get_snip(self):
self.configure(cursor='cross')
self.attributes('-fullscreen', True)
self.attributes('-alpha', 0.4)
self.canvas = tk.Canvas(self, bg='dark gray')
self.canvas.pack(fill='both', expand=True)
self.begin_x = 0
self.begin_y = 0
self.end_x = 0
self.end_y = 0
self.click_drag = False
self.canvas.create_rectangle(0, 0, 0, 0, outline='#0052d6', width=2, fill='white', tags='snip_rect')
self.canvas.bind('<ButtonPress-1>', self.mousePressEvent)
self.canvas.bind('<B1-Motion>', self.mouseMoveEvent)
self.canvas.bind('<ButtonRelease-1>', self.mouseReleaseEvent)
print('Capture the screen...')
def mousePressEvent(self, event):
self.begin_x = event.x
self.begin_y = event.y
print(self.begin_x,self.begin_y)
def mouseMoveEvent(self, event):
self.click_drag = True
self.end_x = event.x
self.cur_y = event.y
width = self.end_x - self.begin_x
height = abs(width * 2/3)
if self.cur_y < self.begin_y:
height *= -1
self.end_y = self.begin_y + height
self.canvas.coords('snip_rect', self.begin_x, self.begin_y, self.end_x, self.end_y)
def mouseReleaseEvent(self, event):
self.destroy()
self.master.update_idletasks()
self.master.after(100) # give time for screen to be refreshed so as not to see the blue box on the screenshot
if not self.click_drag: # if the user just clicks, instead of clicking and dragging
self.begin_x -= 300
self.begin_y += 200
self.end_x = self.begin_x + 600
self.end_y = self.begin_y - 400
x1 = min(self.begin_x, self.end_x)
y1 = min(self.begin_y, self.end_y)
x2 = max(self.begin_x, self.end_x)
y2 = max(self.begin_y, self.end_y)
self.img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
self.image = ImageTk.PhotoImage(self.img)
#self.img = cv2.cvtColor(np.array(img), cv2.COLOR_BGR2RGB)
#cv2.imshow('Captured Image', self.img)
#cv2.waitKey(0)
font1 = ("arial", 18, "bold")
class AcquireImage:
def __init__(self, master):
self.master = master
self.nWin = tk.Toplevel(master)
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(self.nWin, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command =lambda: self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")#, padx=10, pady=10)
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command=lambda: self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")#, padx=10, pady=10)
self.image_selected = None
def show_dialogs(self, method): ################### THIS IS WHERE THE IMAGE IS SELECTED ###########
if method == 1:
ret = filedialog.askopenfilename()
if ret:
self.image_selected = ImageTk.PhotoImage(file = ret)
self.nWin.destroy()
elif method == 2:
newWin = ScreenSnip(self.nWin)
newWin.get_snip()
ret = newWin.image
if ret:
self.image_selected = ret
def main():
root = tk.Tk()
AcquireImage(root)
root.mainloop()
if __name__ == '__main__':
main()
#jasonharper was right. This solution is derived from his comments.
When I create an instance of AcquireImage I also pass ButtonA as a parameter so that I can modify its image. Within AcquireImage I first get a new image (either by snipping it, or with the file explorer) and then to avoid garbage collection immediately deleting it, I save it by assigning it to ButtonA.img. (I first create the .img part of ButtonA in the main program). Once I have the image, I can then assign it.
I probably could have also solved this issue by creating a function
within the main program that changes the image of whatever widget is
passed to it as a parameter. I could then pass this function to the
instance of AcquireImage with ButtonA as a parameter. It might
have looked something like this in the main program: def callback(i_file): ButtonA['image'] = i_file newDialog = snipping_tool.AcquireImage(self.master, self.callback) Later I
would have AcquireImage initialized/defined with
self.some_function as the second argument (after master), and I
could pass the image file to it. At least that's how I probably could
have done it.
This is how I actually solved it:
MAIN APP
import tkinter as tk
import snipping_tool
waitingforImage = True
class MinCodeEx:
global waitingforImage
def __init__(self, master):
self.master = master
self.ButtonA = tk.Button(width=60,height=40,command = lambda: self.UpdateImg())
self.ButtonA.pack()
self.ButtonA.img = None
def UpdateImg(self):
newDialog = snipping_tool.AcquireImage(self.master, self.ButtonA)
def main():
root = tk.Tk()
MinCodeEx(root)
root.mainloop()
if __name__ == '__main__':
main()
snipping_tool.py
import tkinter as tk
from PIL import ImageGrab, ImageTk, Image
from tkinter import filedialog
class ScreenSnip(tk.Toplevel):
def __init__(self, master, changeThis):
super().__init__(master)
self.image = None
self.master = master
self.changeThis = changeThis
def get_snip(self):
self.configure(cursor='cross')
self.attributes('-fullscreen', True)
self.attributes('-alpha', 0.4)
print("attempting to create tk.Canvas for get_snip")
self.canvas = tk.Canvas(self, bg='dark gray')
self.canvas.pack(fill='both', expand=True)
self.begin_x = 0
self.begin_y = 0
self.end_x = 0
self.end_y = 0
self.click_drag = False
self.canvas.create_rectangle(0, 0, 0, 0, outline='#0052d6', width=2, fill='white', tags='snip_rect')
self.canvas.bind('<ButtonPress-1>', self.mousePressEvent)
self.canvas.bind('<B1-Motion>', self.mouseMoveEvent)
self.canvas.bind('<ButtonRelease-1>', self.mouseReleaseEvent)
print('Capture the screen...')
def mousePressEvent(self, event):
self.begin_x = event.x
self.begin_y = event.y
print(self.begin_x,self.begin_y)
def mouseMoveEvent(self, event):
self.click_drag = True
self.end_x = event.x
self.cur_y = event.y
width = self.end_x - self.begin_x
height = abs(width * 2/3)
if self.cur_y < self.begin_y:
height *= -1
self.end_y = self.begin_y + height
self.canvas.coords('snip_rect', self.begin_x, self.begin_y, self.end_x, self.end_y)
def mouseReleaseEvent(self, event):
self.destroy()
self.master.update_idletasks()
self.master.after(100) # give time for screen to be refreshed so as not to see the blue box on the screenshot
if not self.click_drag: # if the user just clicks, instead of clicking and dragging
self.begin_x -= 300
self.begin_y += 200
self.end_x = self.begin_x + 600
self.end_y = self.begin_y - 400
x1 = min(self.begin_x, self.end_x)
y1 = min(self.begin_y, self.end_y)
x2 = max(self.begin_x, self.end_x)
y2 = max(self.begin_y, self.end_y)
self.img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
print("getting image grab")
self.changeThis.img = ImageTk.PhotoImage(self.img)
self.changeThis['image'] = self.changeThis.img
font1 = ("arial", 18, "bold")
class AcquireImage:
def __init__(self, master, changeThis):
self.master = master
self.changeThis = changeThis
self.nWin = tk.Toplevel(master)
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(self.nWin, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command =lambda: self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")#, padx=10, pady=10)
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command=lambda: self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")#, padx=10, pady=10)
self.image_selected = None
def show_dialogs(self, method):
if method == 1:
ret = filedialog.askopenfilename() #filedialog.askopenfilename(initialdir='/home/user/images/')
self.changeThis.img = ImageTk.PhotoImage(file = ret)
self.changeThis['image'] = self.changeThis.img
elif method == 2:
print("attempting ScreenSnip")
newWin = ScreenSnip(self.master, self.changeThis)
newWin.get_snip()
self.nWin.destroy()
def main():
root = tk.Tk()
bt = tk.Button(root, width = 20, height = 20)
bt.pack()
ScreenSnip(root, bt)
#AcquireImage(root,bt)
root.mainloop()
if __name__ == '__main__':
main()
I still need to fix one unrelated thing -- the button doesn't fit the size of the image that I select or grab. It always ends up being a small square.

OpenCV w/ Tkinter : Lag & window problems

I recently started using opencv with tkinter, and I started to have some problems that I can't seem to fix by myself...
The following code is supposed to play a video file while being able to choose which sub-directory you want to sort the file in. The problems I started to have is that the number of frames per seconds seems to act weird, since some clip I play seems "lagging", or don't have the right fps.
Secondly, the code seems really messy, and thus buttons "disappear" after clicking on one for a moment.
And finally, I tried to do something so the buttons get as big as possible to fill the x axis on the bottom of the window, while the main frame, with the video playing, stays the same same size (so the video is supposed to stay in the middle, adapting his height and width to the frame size without changing the ratio) but that doesn't seems to work too.
Any help will be appreciated
PS: I am using Python 3.8 with openCV 4.1.2
Here is the code :
from tkinter import Tk, Button, Label, Frame
import os
import shutil
import cv2
from PIL import Image, ImageTk
x = 0
path = "path/to/folder"
def nbr():
global x
x += 1
text.config(text=files[x])
class ButtonX (Button):
def __init__ (self, *args, folder="", **kwargs):
super().__init__(*args, **kwargs)
self.folder = folder
self.config(command=self.moveTo)
def moveTo(self):
global x
global cap
global width
if cap.isOpened():
cap.release()
shutil.move(path + files[x], path + self.folder + "/" +files[x])
print(files[x] + " moved to " + self.folder)
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
folders = [dI for dI in os.listdir(path) if os.path.isdir(os.path.join(path,dI))]
allfiles = os.listdir(path)
files = [ fname for fname in allfiles if fname.endswith('.webm')]
files.sort(key=len)
print(folders)
window = Tk()
window.resizable(0, 0)
window.geometry("1600x908")
back = Frame(window)
back.grid(row=1, column=1)
window.grid_rowconfigure(0, weight=1)
window.grid_rowconfigure(2, weight=1)
window.grid_columnconfigure(0, weight=1)
window.grid_columnconfigure(2, weight=1)
player = Frame(back)
player.grid(row = 0, column=0)
buttouns = Frame(back)
buttouns.grid(row = 1, column=0)
text = Label(player)
text.grid(row=0, columnspan=4, sticky='w,e,n,s', padx=5, pady=50)
cap = cv2.VideoCapture(path+files[x])
fps = cap.get(cv2.CAP_PROP_FPS)
cap.set(cv2.CAP_PROP_FPS, fps)
print(fps)
height = 600
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
def show_frame():
global cap
global width
cap.set(cv2.CAP_PROP_FPS, fps)
ret, frame = cap.read()
if frame is None:
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image).resize((width, height))
imgtk = ImageTk.PhotoImage(image = img)
text.imgtk = imgtk
text.configure(image=imgtk)
text.after(3, show_frame)
buttons = []
z = 1
y = 0
for i in range(len(folders)):
new_button = ButtonX(buttouns,text=folders[i], width=20, height=2, folder=folders[i])
buttons.append(new_button)
buttons[i].grid(row=z, column=y, sticky='w,e,n,s', padx=5, pady=5)
y += 1
if y == 4:
y = 0
z += 1
def deleted():
global cap
global width
print("deleted " + files[x])
if cap.isOpened():
cap.release()
shutil.move(path + files[x], "path/to/deleted" + files[x])
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
def skipped():
global cap
global width
print(files[x] + " skipped")
if cap.isOpened():
cap.release()
nbr()
cap = cv2.VideoCapture(path+files[x])
ret, frame = cap.read()
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)*(height/cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
delete= Button(buttouns,text="Delete", width=20, height=2, command=deleted, foreground="red")
delete.grid(row=z+1,column=2, columnspan=2, sticky='w,e,n,s', padx=5, pady=5)
skip= Button(buttouns,text="Skip", width=20, height=2, command=skipped)
skip.grid(row=z+1, columnspan=2, sticky='w,e,n,s', padx=5, pady=5)
show_frame()
window.mainloop()

Categories