I am developing an app that displays advertisements. It will display in fullscreen and divide the screen into 2 parts. One part will display an image (or a slide of images). The other part will display a loop of videos, it automatically plays a list of videos in the folder and repeats them. No pause or start button is required but the sound of the video. I have tried with opencv and PIL but it just helps me to play a single video once and play without the video's sound. The code below is what I have used in my project:
ret, frame = self.vid.get_frame()
if ret:
self.photo = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(frame), master=self)
self.videoCanvas.create_image(self.x, self.y, image=self.photo, anchor=CENTER)
self.after(self.delay, self.update)
As I understand, it basically captures all the images in the video and displays them again in order on the canvas.
I am looking for a solution to such problem.
Related
I am trying to display 9 videos onto their own canvases using Tkinter. The problem I am running into is that the window is very laggy and unresponsive. This means nothing else can be done in the application whilst the videos are playing.
I have tried to use a second thread to perform steps 1-3 (as shown below), but this does not seem to help. I am struggling to see how I can make this process more efficient and any help would be much appreciated.
My process for doing this is as follows:
Read the video using cv2
import cv2
cap = cv2.VideoCapture(video_path)
Read a frame from the video
cap.set(1, frame_num)
ret, frame = cap.read()
Resize and convert to PhotoImage
frame = imutils.resize(frame, height=video_height, width=video_width)
photo = ImageTk.PhotoImage(image=Image.fromarray(frame))
Draw the image to canvas
im = self.create_image(0, 0, image=photo, anchor=NW)
This is done for all 9 videos, every 200ms.
The only solution for this is to buy a computer with more CPU cores / GPU / faster CPU, i'm afraid ! If the videos are displayed on a small canvas, you should resize them before playing them. That is, have a already resized video and play that instead of the original one. Reading frame by frame, then resizing and displaying on canvas the frame is very CPU expensive, already for one video, and you do it with 9 ! Thats why the GUI becomes laggy : Your CPU uses all its resources for resizing and playing, and has almost nothing left for responding to user events. A GPU would help there : it takes the part of resizing, which is the most CPU expensive.
On my canvas, I am creating a large number of objects and images, and once loaded, the program finds it hard to maintain this large quantity and frequently crashes. A solution I thought up would be to convert the canvas into an image (perhaps using PIL?), clear the canvas and use canvas.create_image to paste the image-form of the original canvas. I am aware, and have found in similar questions, there are ways to convert the image to a png file/save the file on the PC - I do not want this - I want to turn the image into a PIL image or tkinter PhotoImage.
How can I go about doing this?
Thanks
Well, to begin with, I should admit that it is a pretty long question and I failed to find possible solutions through googling
I have a video in which an intruder tries to intrude into the other side of the fence.
I can track the intruder, but when he is in the other side, I should be able to save the intrusion duration into a file. The intrusion area would be something like this
I thought these steps:
I. Reading a video file;
II. Getting the very first frame displayed,
1. Pausing the video playback;
2. Manually drawing intrusion area on that frame with a mouse; (making draw and reset buttons as events maybe)
3. Replaying the video again
III. Waiting for the intruder to appear, etc. (III part is not important)
So far, I've done I and II (silly, I know) and should accomplish 1,2,3 subparts of step II.
import cv2
file = "intrusion.mp4"
capture = cv2.VideoCapture(file)
ret, firstFrame= capture.read()
while True:
cv2.imshow("First Frame", firstFrame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
I hope you can give your advice and instructions!
PS: refer to any related posts, blogs or links, I am excited to find out
adding cv2.waitKey(0) will pause your while loop indefinitely! It will resume only after any key press.
I think what you're trying to achieve is object tracking using Background Subtraction. Refer Here and see if it fits your requirements.
EDIT:
I guess you want to draw a freehand shape for intrusion area! This Link will guide you to do it. I hope this helps
I can set the background of the main window, and I don't need to worry about the window trying to fit the background image or the image shoving the widgets out of the way.
However when I try to do the same with a frame it becomes a huge mess...
I have tried a few things but everything seams to be related to resizing the image itself and I don't want to warp the image. I want the image to be in the frame and NOT have the frame resize to fit the image.
Is there a way to place the image into the background of the frame without the frame changing in size?
EDIT: Note: The image I am using is large enough to fill the screen so if there is resizing going on by the user the image will cover all the extra space.
So this is how I add a background image to the main window:
bgImage=PhotoImage(file="./Colors/bgImage.png")
bgLable = Label(root,image = bgImage)
bgLable.image = bgImage
bgLable.grid(row=0,column=0,columnspan=3,rowspan=8)
However when I try to do the same thing with a frame it resizes the frame as well:
FrameTL = Frame(root, width = 100)
FrameTL.grid(row = 0, column = 0, rowspan = 20, columnspan = 1, sticky = W+N+S)
TLbg = Label(FrameTL,image = bgImage)
TLbg.image = bgImage
TLbg.grid(row=0,column=0)
There were some other things I tried but they would warp the image to fit the window/frame and I do not want to warp the image.
EDIT:
I have found a work around of sorts. Instead of using frames I used .grid for all my widgets except for the widgets I needed to be on my side menu. The side menu widgets were not aliening to the top left of the window so I was trying to use frames to fix the problem (using .place for now). The frames would work but I could not find a way to make frames transparent so I can keep my background from my root window. And that is why I got stuck on trying to a background image to my frame but without the frame resizing to fit the image.
Is there a way to place the image into the background of the frame without the frame changing in size?
Yes. Use place with relative coordinates. The following will place the label with your image in the center of the root window, and will not affect any other widgets.
some_frame = tk.Frame(root, borderwidth=2, relief="raised", width=200, height=200)
...
background = tk.Label(some_frame, text="I am in the center", background="pink")
background.place(relx=.5, rely=.5, anchor="c")
This is one of the few times when I think place is superior to using grid or pack. This is what the official documentation says about place:
Unlike many other geometry managers (such as the packer) the placer does not make any attempt to manipulate the geometry of the master windows or the parents of slave windows (i.e. it does not set their requested sizes). To control the sizes of these windows, make them windows like frames and canvases that provide configuration options for this purpose.
What I'm trying to do.
Currently I am using PIL too grab a screen shot of my desktop and display the image in a constant loop. This produces a video like effect of screenshots. My intent is analyze each image taken with opencv and display the manipulated results.
What I'm currently doing.
At the moment I have a loop with a 1 millisecond delay taking a screenshot and then displaying it through opencv. Unfortunately grabbing and analyzing the image takes a while and produces the effect I am looking for, but at a lowered frame rate as it takes longer than a millisecond to grab the screenshot and display it.
What I'm looking for.
I'm hoping to asynchronously run this process so that concurrently I can get a smoother frame rate. Unfortunately when I attempt to use Process or threadingon my function I get a warning saying that the action must be taken from the main thread.
How may I be able to make the bellow code async/threaded?
def getImage(bbox):
while True:
#Grab pil image
pil_image = ImageGrab.grab(bbox=(bbox[0], bbox[1], bbox[2], bbox[3])).convert('RGB')
#conver the image to something opencv can use
image = cv2.cvtColor(numpy.array(pil_image), cv2.COLOR_RGB2BGR)
#show the image
cv2.imshow("image", image)
#wait a millisecond so that the image displays
cv2.waitKey(1)
Error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'nextEventMatchingMask should only be called from the Main Thread!'