Error trying to crop frames of a video in OpenCV python - python

I been trying working in a program that crop some parts of a frame in a video with opencv.
the first program works, but when i try to resize the cropped images at some point crash giving me this error:
cv2.error: OpenCV(4.5.2) /tmp/pip-req-build-eirhwqtr/opencv/modules/imgcodecs/src/loadsave.cpp:721: error: (-215:Assertion failed) !_img.empty() in function 'imwrite'
i read that i could be an error of windows, but i try it in Ubuntu and its was the same result, the program pick the data from a csv that saves [frame, x, y]
All its in the main(path, lent) function!
import os
import cv2
import csv
video_path = ''
rl = 0
label = 1
def main(path, lent):
global video_path
global rl
global label
rl = lent
frames = []
coord = []
with open(path, "r") as data:
reader = csv.reader(data, delimiter=',')
for idx, row in enumerate(reader):
if idx == 0:
video_path = row[0]
else:
frames.append(float(row[0]))
coord.append((int(row[1]), int(row[2])))
video = cv2.VideoCapture(video_path)
if not video.isOpened():
print("Error! No file found!")
i = 0
while i < len(frames):
video.set(1, frames[i])
ret, frame = video.read()
img_resized = frame
if not os.path.exists(f"src/data/{video_path[-10:-4]}/resized{rl}"):
os.makedirs(f"src/data/{video_path[-10:-4]}/resized{rl}")
else:
print(i)
img_resized = img_resized[(coord[i][1] - rl):(coord[i][1] + rl), (coord[i][0] - rl):(coord[i][0] + rl)]
cv2.imwrite(f"src/data/{video_path[-10:-4]}/resized{rl}/frame{i}.jpg", img_resized)
i += 1
print("Success!")
video.release()
thanks for the help!

Related

Why does my code using OpenCv extracts less number of frame from a video

When I used below built-in properties of OpenCv to count number of frame of a video, its shows correct result.
video = cv2.VideoCapture(path)
total = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
But, when I tried to save all those frames, its store less number of frames. Below is another code for saving frame-
def ExtractFrames(self, videoPath):
srcVideo = cv2.VideoCapture(videoPath)
try:
if not os.path.exists('VideoFrames'):
os.makedirs('VideoFrames')
except OSError:
print('Error: Creating directory.')
currentframe = 0
while (True):
success, image = srcVideo.read()
if success:
fileName = './VideoFrames/frame' + str(currentframe) + '.jpg'
self.lstVideoFrames.append(fileName)
cv2.imwrite(fileName, image)
currentframe += 1
else:
break

Python cv2 does not write video

Hi i am trying to break a long video down into smaller videos. I got some code of the internet but when I run it it does not write the video what is wrong with my code?
I am not getting any errors.
import cv2
count = 0
if __name__ == '__main__':
vidPath = 'VideoNietBewerkt.mp4'
shotsPath = '/videos/%d.avi' % count
segRange = [(0,1000),(1000,2000),(2000,3000)] # a list of starting/ending frame indices pairs
cap = cv2.VideoCapture(vidPath)
fps = int(cap.get(cv2.CAP_PROP_FPS))
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fourcc = int(cv2.VideoWriter_fourcc('X','V','I','D')) # XVID codecs
for idx,(begFidx,endFidx) in enumerate(segRange):
writer = cv2.VideoWriter(shotsPath,fourcc,fps,size)
cap.set(cv2.CAP_PROP_POS_FRAMES,begFidx)
ret = True # has frame returned
while(cap.isOpened() and ret and writer.isOpened()):
ret, frame = cap.read()
frame_number = cap.get(cv2.CAP_PROP_POS_FRAMES) - 1
if frame_number < endFidx:
writer.write(frame)
else:
break
writer.release()
count += 1
The problem was that I did not closed my cap variable I fixed this by putting everything in the for loop
import cv2
vidPath = 'VideoNietBewerkt.mp4'
segRange = [(0,5000),(5000,50000),(50000,100400)] # <-- to fit my sample movie
for idx,(begFidx,endFidx) in enumerate(segRange):
cap = cv2.VideoCapture(vidPath) # <---- Open Cap
fps = int(cap.get(cv2.CAP_PROP_FPS))
size = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fourcc = int(cv2.VideoWriter_fourcc(*'jpeg'))
shotsPath = f'movie_{str(idx)}.avi' # <-- use idx for naming the output file
print(f'saving file: {shotsPath}')
writer = cv2.VideoWriter() # <-- instantiate the writer this way
writer.open(shotsPath, fourcc, fps, size) # <-- open the writer
cap.set(cv2.CAP_PROP_POS_FRAMES, begFidx)
while(cap.isOpened() and writer.isOpened()): # removed and ret
ret, frame = cap.read()
frame_number = cap.get(cv2.CAP_PROP_POS_FRAMES) - 1
if frame_number < endFidx:
writer.write(frame)
else:
break
writer.release()
cap.release() #<--- Closed Cap
It seems like there is a problem with the codec (at least for me) and with the output filename, which is not updated outside the loop.
I made some changes for working on my machine, try this out with a short movie, there are few comments in the code itself.
This worked for me:
import cv2
vidPath = 'movie.mp4'
segRange = [(0,30),(30,60),(60,90)] # <-- to fit my sample movie
cap = cv2.VideoCapture(vidPath)
fps = int(cap.get(cv2.CAP_PROP_FPS))
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fourcc = int(cv2.VideoWriter_fourcc(*'jpeg')) # <-- I had to change the codec
for idx,(begFidx,endFidx) in enumerate(segRange):
shotsPath = f'movie_{str(idx)}.avi' # <-- update filename here, use idx for naming the output file
print(f'saving file: {shotsPath}')
writer = cv2.VideoWriter() # <-- instantiate the writer this way
writer.open(shotsPath, fourcc, fps, size) # <-- open the writer
cap.set(cv2.CAP_PROP_POS_FRAMES, begFidx)
while(cap.isOpened() and writer.isOpened()): # removed and ret
ret, frame = cap.read()
frame_number = cap.get(cv2.CAP_PROP_POS_FRAMES) - 1
if frame_number < endFidx:
writer.write(frame)
else:
break
writer.release()
cap.release()

Cv2.error : (-215:Assertion failed) !_img.empty() in function 'imwrite'

I am trying to segment images based on their label tag as helmet, non-helmet or unprocessed images for my project. But there is error saying image object is null. I have already made a secondary script where I processed over the same image which is working.I don't know why but it seems opencv library is unable to read one particular image. Any help will be really appreciated.
import requests
import shutil
import json
import sys
import os
import cv2
x=0
lis=[]
s=""
def batwara(filename,data):
print("unproccesed/"+filename[6:])
print(data)
image = cv2.imread(filename)
if image is None:
print("NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN")
return
color = (255, 0, 0)
thickness = 2
totfaces = data['annotation']
if totfaces is None:
cv2.imwrite("unproccesed/"+filename[6:],image)
return
x=0
for face in totfaces:
x=x+1
new_file=str(x)+filename[9:]
print(new_file)
label= face['label']
print ("label=============",label)
wid=face['imageWidth']
hei=face['imageHeight']
x1=int(face['points'][0]['x']*wid)
y1=int(face['points'][0]['y']*hei)
x2=int(face['points'][1]['x']*wid)
y2=int(face['points'][1]['y']*hei)
#print (x1,y1,x2,y2,wid,hei)
start_point = (x1, y1)
end_point = (x2, y2)
crop_img = image[y1:y2, x1:x2]
if len(label)==0:
new_file= "unidentified/img"+new_file
cv2.imwrite(new_file,crop_img)
elif label[0] == "Without Helmet":
new_file= "non_helmet/img"+new_file
cv2.imwrite(new_file,crop_img)
elif label[0] == "With Helmet":
new_file= "helmet/img"+new_file
cv2.imwrite(new_file,crop_img)
with open('/home/oem/Downloads/Bikers Wearing Helmet Or Not.json') as f:
while True:
c = f.read(1)
s=s+c
if c=='{' or c=='[':
lis.append(c)
if c==']'or c=='}':
lis.pop()
if len(lis)==0:
x=x+1
#print(filename)
#print(s)
data = json.loads(s)
filen,ex= os.path.splitext(data['content'])
filename= "image/img"+str(x)+ex
#print(data)
#print (data['content'])
# This is the image url.
image_url = data['content']
# Open the url image, set stream to True, this will return the stream content.
resp = requests.get(image_url, stream=True)
# Open a local file with wb ( write binary ) permission.
local_file = open(filename, 'wb')
# Set decode_content value to True, otherwise the downloaded image file's size will be zero.
resp.raw.decode_content = True
# Copy the response stream raw data to local image file.
shutil.copyfileobj(resp.raw, local_file)
# Remove the image url response object.
del resp
if ex!=".png":
batwara(filename,data)
s=""
if not c:
print ("End of file")
print(x)
break
The error displayed on the terminal is:
Traceback (most recent call last):
File "app2.py", line 91, in <module>
batwara(filename,data)
File "app2.py", line 46, in batwara
cv2.imwrite(new_file,crop_img)
cv2.error: OpenCV(4.2.0) /io/opencv/modules/imgcodecs/src/loadsave.cpp:715: error: (-215:Assertion failed) !_img.empty() in function 'imwrite'
You need to make sure that x1 == x2 or y1 == y2

Python: take screenshot from video

The idea is that, user should be able to load a video from their local machine and tell the program to take a screenshot from the video every 5sec or 30sec. Is there any library to help me with this task? Any idea from how to proceed would be helpful.
install opencv-python (which is an unofficial pre-built OpenCV package for Python) by issuing the following command:
pip install opencv-python
# Importing all necessary libraries
import cv2
import os
import time
# Read the video from specified path
cam = cv2.VideoCapture("C:/Users/User/Desktop/videoplayback.mp4")
try:
# creating a folder named data
if not os.path.exists('data'):
os.makedirs('data')
# if not created then raise error
except OSError:
print('Error: Creating directory of data')
# frame
currentframe = 0
while (True):
time.sleep(5) # take schreenshot every 5 seconds
# reading from frame
ret, frame = cam.read()
if ret:
# if video is still left continue creating images
name = './data/frame' + str(currentframe) + '.jpg'
print('Creating...' + name)
# writing the extracted images
cv2.imwrite(name, frame)
# increasing counter so that it will
# show how many frames are created
currentframe += 1
else:
break
# Release all space and windows once done
cam.release()
cv2.destroyAllWindows()
the above answer is partially right but time.sleep here does not help at all but rather it makes the process slower. however, if you want to take a screenshot at a certain time of a video you need to understand that every time you do "ret, frame = cam.read()" it reads the next frame of the video. every second in a video has a number of frames depends on the video. you get that number using:
frame_per_second = cam.get(cv2.CAP_PROP_FPS)
so if you need to take a screenshot of the 3rd second you can keep the iteration as is in the above answer and just add
if currentframe == (3*frame_per_second):
cv2.imwrite(name, frame)
this will take a screenshot of the first frame in the 3rd second.
#ncica & Data_sniffer solution remake
import cv2
import os
import time
step = 10
frames_count = 3
cam = cv2.VideoCapture('video/example.MP4')
currentframe = 0
frame_per_second = cam.get(cv2.CAP_PROP_FPS)
frames_captured = 0
while (True):
ret, frame = cam.read()
if ret:
if currentframe > (step*frame_per_second):
currentframe = 0
name = 'photo/frame' + str(frames_captured) + '.jpg'
print(name)
cv2.imwrite(name, frame)
frames_captured+=1
if frames_captured>frames_count-1:
ret = False
currentframe += 1
if ret==False:
break
cam.release()
cv2.destroyAllWindows()
#a generic function incorporating all the comments mentioned above.
def get_frames(inputFile,outputFolder,step,count):
'''
Input:
inputFile - name of the input file with directoy
outputFolder - name and path of the folder to save the results
step - time lapse between each step (in seconds)
count - number of screenshots
Output:
'count' number of screenshots that are 'step' seconds apart created from video 'inputFile' and stored in folder 'outputFolder'
Function Call:
get_frames("test.mp4", 'data', 10, 10)
'''
#initializing local variables
step = step
frames_count = count
currentframe = 0
frames_captured = 0
#creating a folder
try:
# creating a folder named data
if not os.path.exists(outputFolder):
os.makedirs(outputFolder)
#if not created then raise error
except OSError:
print ('Error! Could not create a directory')
#reading the video from specified path
cam = cv2.VideoCapture(inputFile)
#reading the number of frames at that particular second
frame_per_second = cam.get(cv2.CAP_PROP_FPS)
while (True):
ret, frame = cam.read()
if ret:
if currentframe > (step*frame_per_second):
currentframe = 0
#saving the frames (screenshots)
name = './data/frame' + str(frames_captured) + '.jpg'
print ('Creating...' + name)
cv2.imwrite(name, frame)
frames_captured+=1
#breaking the loop when count achieved
if frames_captured > frames_count-1:
ret = False
currentframe += 1
if ret == False:
break
#Releasing all space and windows once done
cam.release()
cv2.destroyAllWindows()
To add on data_sniffer's answer. I would recommend using round (Math function) on frame_per_second when checking as if the frame rate is a decimal number then it will go into an infinite loop.
The solutions provided do not work for me in several cases.
The FPS from cv2.CAP_PROP_FPS is a floating point value and the FPS rate of my testvid.mp4 was 23.976023976023978 according to this property.
When looping through current_frame / fps % 3, we will almost always have leftovers because of this floating point value. Same goes for (3*frame_per_second):, causing our imwrite to never be reached.
I solved this issue by using the same calculations, but storing the remainders and comparing those:
current_frame = 0
fps_calculator_previous = 0
while (True):
ret, frame = cam.read()
if ret:
# Still got video left.
file_name = f"./data_generation/out/{_fn}-{current_frame}.jpg"
fps_calculator = (current_frame / fps) % every_x_sec
if(fps_calculator - fps_calculator_previous < 0):
print("Found a frame to write!")
cv2.imwrite(file_name, frame)
fps_calculator_previous = fps_calculator
current_frame += 1
else:
break
This seems to work well for me with any value for both cv2.CAP_PROP_FPS as well as every_x_sec
My video was 18 minutes and 7 seconds long, and I captured 362 unique frames from that with every_x_sec set to 3.
Edited #ncica's code and noted that it is working fine.
import cv2
import os
import time
cam = cv2.VideoCapture("/path/to/videoIn.mp4")
try:
if not os.path.exists('data'):
os.makedirs('data')
except OSError:
print('Error: Creating directory of data')
intvl = 2 #interval in second(s)
fps= int(cam.get(cv2.CAP_PROP_FPS))
print("fps : " ,fps)
currentframe = 0
while (True):
ret, frame = cam.read()
if ret:
if(currentframe % (fps*intvl) == 0):
name = './data/frame' + str(currentframe) + '.jpg'
print('Creating...' + name)
cv2.imwrite(name, frame)
currentframe += 1
else:
break
cam.release()
cv2.destroyAllWindows()
The trick is it is looping frame-by-frame.
So, here we are capturing frames that we want and write disk as snapshot image file.
eg : If you want snapshot two second by two second intvl must be 2

OpenCV VideoWriter silently stops after a time

After writing videos successfully for awhile, VideoWriter will silently start creating only empty video files.
This is on a Raspberry PI 3
OpenCV 2.4.9
The following script illustrates the issue:
Here's a standalone script that illustrates the issue:
#!/usr/bin/pyton
import cv2
import time
import numpy
import subprocess
fourcc = cv2.cv.CV_FOURCC(*'MJPG')
allret = 0
f = numpy.ones((480,640,3), numpy.uint8)
h,w,c = f.shape
print h,w,c
counter = 0
while True:
counter += 1
print "Iteration: ", counter
time.sleep(0.1)
writer = cv2.VideoWriter("test.avi", fourcc, 5, (w,h))
for i in xrange(20):
writer.write(f)
writer.release()
writer = None
ret = subprocess.call(["avprobe","test.avi"])
allret += ret
print "FAILURES:", allret
if allret > 5:
break
After about 800 or so successful videos we then only get bad videos. Restarting the scripts starts the process over.

Categories