Convert video into individual frames using Python without ffmpeg? - python

I need to compare 2 videos to check whether they are the same.
So I am planning to do the following:
Split both the videos into individual frames
Compare each frame with the corresponding frame of the ref video using Python Image Lib
Count the number of different frames to decide whether they are same.
I would like to know whether there is any function in Python to help me with the first step, i.e., to split the video into individual frames. I do not want to use ffmpeg to do the splitting.
Thanks in advance for the help

You can use opencv
import cv2
video_capture = cv2.VideoCapture("rtsp://admin:admin#192.168.0.94:554/stream3")
while True:
# get frame by frame
ret, frame = video_capture.read()
cv2.imwrite('pic.png',frame)
cv2.imshow('Video', frame)

Try this:
currentFrame = 0
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Saves image of the current frame in jpg file
name = './data/frame' + str(currentFrame) + '.jpg'
print ('Creating...' + name)
cv2.imwrite(name, frame)
# To stop duplicate images
currentFrame += 1
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
#you can use this method

Related

Using OpenCV to take a particular amount of images without pressing any key

I wish to write a program for face recognition. I want my program to automatically take a specific number of images(say,5). Here is what I am currently doing:
import cv2
cam=cv2.VideoCapture(0)
a=0
count=0
for a in range(5):
ret,img=cam.read()
cv2.imshow("Test",img)
if not ret:
break
k=cv2.waitKey(1)
print("Image"+str(count)+"saved")
file='C:/Users/User/Desktop/FACEREC/known_faces/img_test/ad2'+str(count)+'.jpg'
cv2.imwrite(file,img)
a+=1
cam.release()
cv2.destroyAllWindows()
cam.release()
cv2.destroyAllWindows()
It shows "Image 0 saved" five times but in the folder(ad2), there is only a single image. Need some guidance.
Thank you
Lets start interpreting the code line-by-line:
Variable initialization
import cv2
cam=cv2.VideoCapture(0)
a=0
count=0
You load the opencv library and initialize the cam variable for webcam display. Then both a and count are intialized to 0. Now count variable is understandable, most probably count count the frames. What does a do?
Display and save frames
First-part
for a in range(0, 5):
ret,img=cam.read()
cv2.imshow("Test",img)
if not ret:
break
variable a declared again so we don't need to intialize at the beginning. Then current web-frame is being fetched. The frame is given as an input to imshow without even the current frame returned or not. The correct logic should be:
for a in range(5):
ret,img=cam.read()
if ret:
cv2.imshow("Test",img)
Second-part
k=cv2.waitKey(1)
print("Image"+str(count)+"saved")
file='C:/Users/User/Desktop/FACEREC/known_faces/img_test/ad2'+str(count)+'.jpg'
cv2.imwrite(file,img)
a+=1
Now, the k variable is initialized as a key for quiting the program when a key is pressed. Say, when q is pressed program terminates.
k=cv2.waitKey(1) & 0xFF
if k == ord('q'):
break
But if you break during the process, then you can't save the images. Therefore break should be at the end of the line.
For the rest of the code, you can use a as a counter. If you specify the start and end values. For each value a is increased by one. Then you can use it to discriminate the frames.
Code:
# Load the library
import cv2
# Initialize webcam
cam = cv2.VideoCapture(0)
# Save the frames
for a in range(0, 5):
# Get current frame
ret, img=cam.read()
# If frame is returned
if ret: 
# Set the file-name
file='C:/Users/User/Desktop/FACEREC/known_faces/img_test/ad2' + str(a) + '.jpg'
# Write the frame
cv2.imwrite(file, img)
# Inform the user
print("Image" + str(a) + "saved")
# Display the frame
cv2.imshow("Test", img)
# If q is pressed quit
k=cv2.waitKey(1) & 0xFF
if k == ord('q'):
break
# Release the object
cam.release()
# Close the window
cv2.destroyAllWindows()

Frame from video is upside down after extracting

My problem here is that when I extracting a video into a frame using opencv, sometimes the frame that I get will flip up which happened to me for both my machine(window) and VM(ubuntu) But some of the video I tested, frames are not flip. So, I wonder what factor or what should be changed/added in my code to make the extract fixed without a flip
def extract_frame(video,folder):
global fps
os.mkdir('./green_frame/{folder}/'.format(folder=folder))
vidcap = cv2.VideoCapture(video)
success,image = vidcap.read()
fps = vidcap.get(cv2.CAP_PROP_FPS)
count = 0
success = True
while success: #os.path.join(pathOut,(name+'.png'))
cv2.imwrite(os.path.join('./green_frame/{folder}/'.format(folder=folder),"frame%d.png" % count), image)
success,image = vidcap.read()
print('Read a new frame: ', success)
count += 1
This is the example of frame I get from this code.
Which my orginal video that I used is upside down like this:
So, in my case, what I have to changed to make it not flip like my first picture. Is it relate to the resolution or framerate of the video? I tested with a 1280x720 resolution video and all of the frame extracted are flipped upside down but a frame from video with a 568x320 is normal
Thank you
Edit:
So, I look at the information of the video and I found out that in the metadata, it has rotate 180 for the video that extract to an upside down frame
But when I check with a normal video that produced a non upside-down frame, it does not have rotate:180
So from this, how can I deal with a video that has a rotation?
Update
This problem can now be solved by simply updating to OpenCV v4.5 and above.
If upgrading is a problem follow the old answer, below.
For anyone still looking into this, I was just stuck on the same problem. Turns out some Android phones and iPhones take images/frames in landscape and convert them on the fly according to the exif 'rotate' tag to display the images/frames.
Weird design choice in OpenCV is that cv2.imread(img_file) already reads the image in correct orientation by reading the image's rotate tag, but the cv2.VideoStream's read() method does not do this.
So, to fix this I used ffmpeg to read the 'rotate' tag and rotate the video frame to its correct orientation.(Big thanks to the comments above, for pointing me in the right direction 👍)
Following is the code:
Make sure you have ffmpeg for python. (pip install ffmpeg-python)
Create a method to check if rotation is required by the video_file:
import ffmpeg
def check_rotation(path_video_file):
# this returns meta-data of the video file in form of a dictionary
meta_dict = ffmpeg.probe(path_video_file)
# from the dictionary, meta_dict['streams'][0]['tags']['rotate'] is the key
# we are looking for
rotateCode = None
if int(meta_dict['streams'][0]['tags']['rotate']) == 90:
rotateCode = cv2.ROTATE_90_CLOCKWISE
elif int(meta_dict['streams'][0]['tags']['rotate']) == 180:
rotateCode = cv2.ROTATE_180
elif int(meta_dict['streams'][0]['tags']['rotate']) == 270:
rotateCode = cv2.ROTATE_90_COUNTERCLOCKWISE
return rotateCode
Create a method to correct the rotation of the frame in video file:
def correct_rotation(frame, rotateCode):
return cv2.rotate(frame, rotateCode)
Finally, do this in your main loop:
# open a pointer to the video file stream
vs = cv2.VideoCapture(video_path)
# check if video requires rotation
rotateCode = check_rotation(video_path)
# loop over frames from the video file stream
while True:
# grab the frame from the file
grabbed, frame = vs.read()
# if frame not grabbed -> end of the video
if not grabbed:
break
# check if the frame needs to be rotated
if rotateCode is not None:
frame = correct_rotation(frame, rotateCode)
# now your logic can start from here
Hope this helps 🍻
Sometimes the following will solve the problem of opening some videos upside-down.
cap = cv2.VideoCapture(path, apiPreference=cv2.CAP_MSMF)
When I recently ran into this issue, I found that all that was required was to update to OpenCV v4.5:
This is the related Github issue: https://github.com/opencv/opencv/issues/15499
Here is the commit: https://github.com/opencv/opencv/commit/f0271e54d90b3af62301f531f5f00995b00d7cd6
The rotate tag is optional so the check_rotation will fail,
This code fix it:
def check_rotation(path_video_file):
# this returns meta-data of the video file in form of a dictionary
meta_dict = ffmpeg.probe(path_video_file)
# from the dictionary, meta_dict['streams'][0]['tags']['rotate'] is the key
# we are looking for
rotate_code = None
rotate = meta_dict.get('streams', [dict(tags=dict())])[0].get('tags', dict()).get('rotate', 0)
return round(int(rotate) / 90.0) * 90
I would just do this in your frame processing loop:
frame = cv2.flip(frame,0)
The 0 flips vertically, see Open CV documentation for more info.

I am trying to build Motion Detector using openCV and python but display window is not responding when I terminate program

Here is the code for the same, have a look at it. In this, below code I am creating a Motion Detector and with this I will be recording the timings of when the various objects appeared and disappeared for which I am using dataframe.
The issue with this is that the program executes but when the output is displayed in the form of a Window, it freezes when I try to terminate.
import cv2, pandas
from datetime import datetime
first_frame = None
status_list = [None,None]
times = []
df = pandas.DataFrame(columns=["Start", "End"]) #Dataframe to store the time values during which object detection and movement appears.
video = cv2.VideoCapture(0)#VideoCapture object is used to record video using web cam
while True:
#check is a bool data type, returns true if VideoCapture object is read
check,frame = video.read()
status = 0
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) # For converting the frame color to gray scale
gray = cv2.GaussianBlur(gray,(21,21),0) # For converting the gray scale frame to GaussianBlur
if first_frame is None:
first_frame = gray # used to store the first image/frame of the video
continue
delta_frame = cv2.absdiff(first_frame,gray)#calculates the difference between first and other frames
thresh_delta = cv2.threshold(delta_frame,30,255,cv2.THRESH_BINARY)[1]
thresh_delta = cv2.dilate(thresh_delta,None,iterations=0) #Provides threshold value, so if the difference is <30 it will turn to black otherwise if >30 pixels will turn to white
(_,cnts,_) = cv2.findContours(thresh_delta.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #Define the contour area,i.e. adding borders
#Removing noises and shadows, any part which is greater than 1000 pixels will be converted to white
for contour in cnts:
if cv2.contourArea(contour) < 1000:
continue
status = 1 #change in status when the object is detected
#Creating a rectangular box around the object in frame
(x,y,w,h) = cv2.boundingRect(contour)
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),3)
#list of status for every frame
status_list.append(status)
status_list=status_list[-2:]
#Record datetime in a list when change occurs
if status_list[-1]==1 and status_list[-2]==0:
times.append(datetime.now())
if status_list[-1]==0 and status_list[-2]==1:
times.append(datetime.now())
cv2.imshow('frame',frame)
#cv2.imshow('Capturing',gray)
#cv2.imshow('delta',delta_frame)
#cv2.imshow('thresh',thresh_delta)
key = cv2.waitKey(1) #changing the frame after 1 millisecond
#Used for terminating the loop once 'q' is pressed
if key == ord('q'):
break
print(status_list)
print(times)
for i in range(0,len(times),2):
df = df.append({"Start":times[i],"End":times[i+1]},ignore_index=True)
df.to_csv("Times.csv")
video.release()
cv2.destroyAllWindows #will be closing all the windows
Try this:
if cv2.waitKey(1) & 0xFF == ord('q'):
break
For a brief explanation about what "& 0xFF" is, see: What's 0xFF for in cv2.waitKey(1)?
It is basically a bit mask that takes the portion of 'waitKey' value(32 bit) that can be compared to ASCII (8 bit).
You can try this.
k = cv2.waitKey(1) & 0xFF
if k == 27 :
break
where k can be any ASCII code on the keyboard ASCII code help
In this case 27 is 'Esc' button.
However, the problem you're having where it is freezing, have you tried continuously pressing any button besides q? I had a similar problem when I was testing out OpenCV's tutorial code here
but i figured it out by playing around and then realizing i needed to hold down any button besides the 'exit' button.
I had faced the same issue bcz of this piece of code from geeksforgeeks
Please chck the last line of the code:
cv2.destroyAllWindows #will be closing all the windows
Add parenthesis, it shud b:
cv2.destroyAllWindows()
Please try this, rest looks fine
Well you can also pass a particular frame that you want to close like:
cv2.destroyAllWindows("frame")

cv2.VideoCapture on python

I am running the following code:
import numpy as np
import cv2
import os
count = 0
cap = cv2.VideoCapture("/home/simon/PROJECT/real_data/00000020.mp4")
while not cap.isOpened():
cap = cv2.VideoCapture("./00000020.mp4")
cv2.waitKey(1000)
print "Wait for the header"
pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
while True:
flag, frame = cap.read()
if flag:
# The frame is ready and already captured
cv2.imshow('video', frame)
pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
print str(pos_frame)+" frames"
else:
# The next frame is not ready, so we try to read it again
cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1)
print "frame is not ready"
# It is better to wait for a while for the next frame to be ready
cv2.waitKey(1000)
if cv2.waitKey(10) & 0xFF == 27:
break
if cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) == cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT):
# If the number of captured frames is equal to the total number of frames,
# we stop
break
if ret == True:
frame = cv2.VideoCapture.grab()
frame = 'frame%d' % count
cv2.imwrite('frame%d.png', frame)
count += 1
else:
print 'stopped at' + count
break
And whenever I run it, it loops on the while not loop, printing "wait for header".
There is never an error code or anything like that either.
I have tried to run it as a more simple piece of code, where it doesnt have all these checks, and again that doesn't throw any errors.
I am attempting to run this code to open a video, and then save the frames as png files throughout the video.
Does anyone spot any particular problems with the code?
Or alternatively does anyone know a piece of code that would do what i want more efficiently, as I have trawled through google searches and stack overflow a lot recently and haven't found anything
Thanks in advance
Panda
You need to include a couple of DLLs in your python directory in order to play videos. Please see this for details:
https://li8bot.wordpress.com/2014/07/09/opencvpython-part-1-working-with-videos/

Start video read from a particular frame

I have obtained the frame_count of a saved video.
self.frame_count = self.capture.get(cv.CV_CAP_PROP_FRAME_COUNT) - 1
Now, I want to start a frame read from a particular frame_count. How do I do this?
Reason: I need to track an object and I have found the location of the object I want to track using HSV image segmentation. Now to track it, I intend to start the video from that particular frame and set the track window to the objects' coordinates.
Want: It should not be redundant and computationally intensive.
Use the below code to accomplish your task.
The Opencv version you are using is old. Use Opencv2.
Link : http://docs.opencv.org/trunk/doc/py_tutorials/py_tutorials.html
import numpy as np
import cv2
import os
cam = cv2.VideoCapture('full_path/bird.avi')
i = 1
initialize_first_frame = cam.read()[1]
start_from_frame = 5
dir = './testImages/'
os.makedirs(dir)
while True:
if(i>=start_from_frame):
cv2.imshow('Frame Conversion',cam.read()[1])
cv2.imwrite(dir + "/image-"+str(i).zfill(5)+".png",cam.read()[1])
i = i + 1
key = cv2.waitKey(10)
if key == 27:
cv2.destroyWindow('Frame Conversion')
break
print "End"
I hope this is the code you want.
Try the following:
f = # put here the frame from which you want to start
self.capture.set(CV_CAP_PROP_POS_FRAMES, f)
while f < self.frame_count:
retval, image = self.capture.read()
f += 1
For any version 3 and 4 of OpenCV Python, follow this -
import cv2
# suppose you want to start reading from frame no 500
frame_set_no = 500
cap = cv2.VideoCapture("full_path/cow.mp4")
# capture is set to the desired frame
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_set_no)
while True:
ret, frame = cap.read()
cv2.imshow("Video", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()

Categories