Comparing current and previous frame photos - Python [closed] - python

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I use python to record the writing process (from 0 to the end), and use opencv to convert the writing video into many frames. But when observing the results, I found that sometimes 2-3 frames of pictures are equal. I want to keep only the first picture that is equal when writing the file, and add the timeline. Can any experts give me some advice? The following is my code:
#cv2
import numpy as np
import cv2
from PIL import Image
def get_images_from_video(video_name, time_F):
video_images = []
vc = cv2.VideoCapture(video_name)
c = 1
#判斷是否開啟影片
if vc.isOpened():
rval, video_frame = vc.read()
else:
rval = False
#擷取視頻至結束
while rval:
rval, video_frame = vc.read()
#每隔幾幀進行擷取
if(c % time_F == 0):
video_images.append(video_frame)
c = c + 1
vc.release()
return video_images
#time_F越小,取樣張數越多
time_F = 24
#影片名稱
video_name = 'writingvideo2/11_0330吳恒基.mp4'
#numpy
#讀取影片並轉成圖片
video_images = get_images_from_video(video_name, time_F)
crop_img=[]
#顯示出所有擷取之圖片
for i in range(0,len(video_images)):
#i_str=str(i)
#cv2.imshow('windows',video_images[i])
x=50
y=150
w=1800
h=650
crop_img.append(video_images[i][y:y+h,x:x+w])
cv2.imshow("cropped", crop_img[i])
#correct write path
i_str=str(i)
filename='output2/image/11/'+i_str+'.png'
cv2.imwrite(filename, crop_img[i], [cv2.IMWRITE_JPEG_QUALITY, 90])
cv2.waitKey(100)
cv2.destroyAllWindows
So I want is, if they are equal, keep the previous frame and discard the current photo

You need to employ some kind of a metric which calculates the similarity between two consecutive frames. This is well studied problem and you can gain a lot of insight by reading this question.
Image comparison - fast algorithm
But be aware that dropping frames from your video will change the speed and thus the length of the video.

Related

Wait for input() to be called second times [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 hours ago.
Improve this question
I'm new to python. I am trying to use a qr scanner to scan qr code as input name to start recording video. And scan the same qr for the second time to end the recording. But I can't find a way to calculate the input() to be called second time. Please help, thank you.
import cv2
cap= cv2.VideoCapture(0)
width= int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height= int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
count = 0
filename = input()
writer= cv2.VideoWriter('/home/zikingyong/Python/mp4/' + filename + '.mp4', cv2.VideoWriter_fourcc(*'DIVX'), 20, (width,height))
while True:
ret,frame= cap.read()
writer.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == 27:
print(x)
break
cap.release()
writer.release()
cv2.destroyAllWindows()

How can I convert a return statement into something that can be used by Tkinter [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
This post was edited and submitted for review 7 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I am making a GFC (Greatest Common Factor) calculator with GUI, but my current code only works with a return statement, and tkinter doesn't accept return to fill a textbox widget.
Here is a sample of my code
def gproces():
Gnumber1 = Entry.get(GE1)
Gnumber2 = Entry.get(GE2)
Gnumber1 = int(Gnumber1)
Gnumber2 = int(Gnumber2)
if Gnumber1 > Gnumber2:
Gnumber1, Gnumber2 = Gnumber2, Gnumber1
for x in range (Gnumber1, 0, -1):
if Gnumber1 % x == 0 and Gnumber2 % x == 0:
return x
Here is where it's supposed to be used: (To fill GE3)
GE3=Entry(top, bd =5)
GE3.grid(row=3, column=4)
GB=Button(top, text ="Submit", command = gproces).grid(row=4,column=4,)
How do I convert a return statement into something that can be used by Tkinter?
You can just insert the result into the text box inside gprocess():
def gproces():
# better cater invalid input
try:
Gnumber1 = int(GE1.get())
Gnumber2 = int(GE2.get())
x = min(Gnumber1, Gnumber2)
for x in range(x, 0, -1):
if Gnumber1%x == 0 and Gnumber2%x == 0:
break
# insert result into text box
GE3.delete(0, 'end')
GE3.insert('end', x)
except ValueError:
print('Invalid number input')
Note that there is math.gcd() to find the GCF.
Ok so if I understand this correctly you want the result to be displayed in a textbox.
This code should work:
T.delete('1.0', tk.END) # deletes all previous data
T.insert('1.0', str(x)) # inserts new data
Where T is your textbox.
If you want to fill the Textbox in a loop you can simply run T.insert('1.0', str(x)) instead of using return at the end of your function, or you can use both return and T.insert, but don't forget to clear the textbox at the begining of the function with T.delete.

How to add simple graphics to a game to add scrolling text on screen? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am making a text adventure game and want to be able to have graphics that make the text go on the screen and scroll through like undertale text. How can I do this?
This solution here works.
from tkinter import *; # Import the Tk library.
import time; # So that we can use the time library
import math; # And perform maths operations
tk = Tk(); # Make a new window
tk.title("Not Undertale"); # Set the title of the window. You can change this if you like.
canvas = Canvas(tk, width=600, height=400); # Make a canvas that we can put the text on. You can play around with the numbers if you like.
canvas.pack(); # This basically tells Tk to find somewhere to put the canvas.
text = " Hello. This goes on forever."; # This is the message that will scroll across the screen. You can change this, although I reccommend putting at least on space either before or after the text.
txt = canvas.create_text(300, 200, text = " ", font = ("Monospace", 12)); # This creates the item that will hold the widget. Again, you can play around with the numbers. The font is Monospace size 12, this is optional. I reccommend using a fixed-width font for this though.
timer = 0; # The timer.
count = 0; # A variable that we will use later.
while True:
try:
tk.update(); # The reason this is in a Try/Except statement is because you get errors when you close the window, so we want to ignore that and finish the program.
except:
break;
time.sleep(0.05); # Wait a bit before drawing the next frame
timer += 0.05; # And add a bit to timer
count = math.floor(timer * 4) % len(text); # This is where we use the count variable. Basically this changes by 1 every frame, we use this to find what part of the text we're writing.
if count > len(text): # If the count variable is more than the length of the text, set it to 0.
count = 0; # I'm positive we don't need this bit, but it's in there just in case.
display_txt = ""; # This is a temporary variable where we store the scrolling letters.
c = count; # Copy the count variable to one called c
while c < count + 10: # While c is between count and ten more than count.
display_txt += text[c % len(text)]; # We add a letter to display_txt
c += 1; # And add one to c.
canvas.itemconfig(txt, text = display_txt); # The last thing we need to do is change the content of the text item so that it displays the scrolled text.
This is probably not the best way of doing it, but it works, and you can experiment with it.

Parse video at lower frame rate

I currently am working on a project where I need to parse a video and pass it through several models. The videos come in at 60fps. I do not need to run every frame through the models. I am running into some issue when trying to skip the unneeded frames. I have tried two methods which are both fairly slow.
Method 1 code snippet:
The issue here is that I am still reading every frame of the video. Only every 4th frames is run through my model.
cap = cv2.VideoCapture(self.video)
while cap.isOpened():
success, frame = cap.read()
if count % 4 !=0:
count += 1
continue
if success:
''Run frame through models''
else:
break
Method 2 code snippet:
This method is slower. I am trying to avoid reading unnecessary frames in this case.
cap = cv2.VideoCapture(video)
count=0
while True:
if count % 4 != 0:
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
count+=1
success, frame = cap.read()
Any advice on how to achieve this in the most efficient way would be greatly appreciated.
Getting and setting frames by changing CV_CAP_PROP_POS_FRAMES is not accurate (and slow) due to how video compression works: by using keyframes.
It might help to not use the read() function at all. Instead use grab() and only retrieve() the needed frames. From the documentation: The (read) methods/functions combine VideoCapture::grab() and VideoCapture::retrieve() in one call.
grab() gets the frame data, and retrieve() decodes it (the computationally heavy part). What you might want to do is only grab frames you want to skip but not retrieve them.
Depending on your system and opencv build, you could also have ffmpeg decode video using hardware acceleration.
As I get it you are trying to process every fourth frame. You are using the condition:
if count % 4 != 0
which is triggered 3 out of 4 frames instead (you are processing frames 1, 2, 3, 5, 6, 7 etc)! Use the opposite:
if count % 4 == 0
Also although code snippets the two method does not seem to process the same frames. Although in both cases your counter seems to increase by 1 in each frame you actually point to the 15xframe of that counter in the second case (cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15).
Some comments on your code also (maybe I misunderstood something):
Case 1:
while cap.isOpened():
success, frame = cap.read()
if count % 4 !=0:
count += 1
continue
here you seem to count only some frames (3 out of 4 as mentioned) since frames which are multiples of 4 are skipped: condition count % 4 !=0 is not met in that case and your counter is not updated although you read a frame. So, you have an inaccurate counter here. It's not shown how and where do you process you frames to judge that part though.
Case 2:
while True:
if count % 4 != 0:
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
count+=1
success, frame = cap.read()
here you read frames only if condition is met so in this code snippet you don't actually read any frame since frame 0 does not trigger the condition! If you update the counter outside the if scope it's not clear here. But if you do you should also read a frame there. Anyway more code should be revealed to tell.
As a general advice you should update the counter everytime you read a frame.
Instead putting a threshold on number of frames, which would make opencv process ALL the frames (which you rightly pointed out, slows the video processing), it's better to use CAP_PROP_POS_MSEC link and offload that processing to cv2. By using this option you can configure cv2 to sample 1 frame every nth Millisecond. So setting subsample_rate=1000 in vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count * subsample_rate)) would sample 1 frame every 1 second (as 1000 milliseconds equals 1 second). Hopefully this improves your video processing speed.
def extractImagesFromVideo(path_in, subsample_rate, path_out, saveImage, resize=(), debug=False):
vidcap = cv2.VideoCapture(path_in)
if not vidcap.isOpened():
raise IOError
if debug:
length = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_COUNT))
width = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_WIDTH))
height = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_HEIGHT))
fps = vidcap.get(cv2.cv2.CAP_PROP_FPS)
print 'Length: %.2f | Width: %.2f | Height: %.2f | Fps: %.2f' % (length, width, height, fps)
success, image = vidcap.read() #extract first frame.
frame_count = 0
while success:
vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count*subsample_rate))
success, image = vidcap.read()
if saveImage and np.any(image):
cv2.imwrite(os.path.join(path_out, "%s_%d.png" % (frame_count)), image)
frame_count = frame_count + 1
return frame_count

I need to count the number of black pixels in a processed video using OpenCV in python [duplicate]

This question already has answers here:
count number of black pixels in an image in Python with OpenCV
(2 answers)
Closed 5 years ago.
I have a live video feed and I have performed perspective transform and background subtraction MOG2. I need to know how many black pixels are there in the frame in real time.
I tried this (snippet from main code), but it doesn't seem to work.
dst1 = cv2.warpPerspective(frame,M,(707,500)) #persp transform 707*500 px
dst = fgbg.apply(dst1) #apply backgdsubtrMOG2
cv2.imshow("outputclr",dst1)
cv2.imshow("outputbgsub",dst)
#find no. of black pixels
for x in range (1,706):
for y in range (1,499):
if dst[x,y] == 0: #would probably work as bkgdsubtrMOG2 has gray-scale output?
count = count + 1
print count
key = cv2.waitKey(10) & 0xFF
if key == 27:
break
I get this error:
Traceback (most recent call last):
File "C:\Users\Niranjan\Desktop\FINAL YEAR PROJECT\Python Codes\CAR WORK\vid2..py", line 73, in <module>
if dst[x,y] == 0:
IndexError: index 500 is out of bounds for axis 0 with size 500
How can I resolve this?
The solution was to use the python standard syntax which goes like this:
if dst[x][y] == [0][0]:
Instead of parenthesis.
credits to #Filip Kilibarda

Categories

Resources