I'm capturing video from my video file using OpenCV on linux. It works fine but when I try to play my captured video it plays too fast. i.e. I capture from video for 10 seconds but when I play on the video is 8 seconds.
Video capture function
def save_frames(video_file, path_in):
cap = cv2.VideoCapture(video_file)
length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
count = 1
while cap.isOpened():
ret, frame = cap.read()
cv2.imwrite(path_in + "frame{}.jpg".format(str(count).zfill(5)), frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
count += 1
cap.release()
cv2.destroyAllWindows()
return fps
Video writer function
def make_video(path_out, outvid, fps=25, size=None, is_color=True,format='mp4v'):
images = [f for f in os.listdir(path_out) if ".png" in f]
from cv2 import VideoWriter, VideoWriter_fourcc, imread, resize
fourcc = VideoWriter_fourcc(*'mp4v')
vid = None
count = 0
for image in images:
if not os.path.exists(path_out + image):
raise FileNotFoundError(image)
img = imread(path_out + image)
if vid is None:
if size is None:
size = img.shape[1], img.shape[0]
vid = VideoWriter(outvid, fourcc, float(fps), size, is_color)
if size[0] != img.shape[1] and size[1] != img.shape[0]:
img = resize(img, size)
vid.write(img)
if count % 100 == 0:
print("Progress: %0.2f%%" % (count / len(images) * 100,), flush=True)
vid.release()
return
I tried different fps (30,25,15,10,5) .These fps didn't works me and for all fps 600 frame captures on 10 sec video .The cv2.CAP_PROP_FPS default capture 30 fps. When I try to change the fps but the frame rate didn't change .please let me know why this happens .Any answers welcome.
1)The problem here is cv2.CAP_PROP_FPS default fps is 30. So, it saves 600 images for 20sec video. To solve this use if count%(1*fps) == 0: before the cv2.imwrite .It saves one frame for each second.
2)Then set the fps = 1 in VideoWriter object. After that video is in normal speed.
Related
I have a mp4/avi videos with duration 10 minutes and FPS 30. I want to reduce duration to 5 mins but FPS still 30. It means that the new videos will drop a half of frame (for example, f0 f2 f4 compare with original video f0 f1 f2 f3 f4). How can I do it on opencv? This is current code to get duration and FPS of the video.
# import module
import cv2
import datetime
# create video capture object
data = cv2.VideoCapture('C:/Users/Asus/Documents/videoDuration.mp4')
# count the number of frames
frames = data.get(cv2.CAP_PROP_FRAME_COUNT)
fps = data.get(cv2.CAP_PROP_FPS)
# calculate duration of the video
seconds = round(frames / fps)
video_time = datetime.timedelta(seconds=seconds)
print(f"duration in seconds: {seconds}")
print(f"video time: {video_time}")
This code will read the input video file, frame by frame, and write every other frame to the output video file. As a result, the output video will have half the number of frames as the input video and therefore, half the duration.
import cv2
# Open the input video file
cap = cv2.VideoCapture("input.mp4")
# Check if the video is opened successfully
if not cap.isOpened():
print("Error opening video file")
# Read the video's width, height, and frame rate
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(cap.get(cv2.CAP_PROP_FPS))
# Create the output video file
out = cv2.VideoWriter("output.mp4", cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height))
# Read the frames from the input video and write them to the output video,
# skipping every other frame
while True:
ret, frame = cap.read()
if not ret:
break
cap.grab()
out.write(frame)
# Release the video capture and video write objects
cap.release()
out.release()
Read frames from the capture, keeping track of how many you've read, and write only every Nth frame, like so:
from itertools import count
import cv2
in_video = cv2.VideoCapture("example.mp4")
frames = int(in_video.get(cv2.CAP_PROP_FRAME_COUNT))
fps = in_video.get(cv2.CAP_PROP_FPS)
w = int(in_video.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(in_video.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"{frames=}, {fps=}, {w=}, {h=}")
out_video = cv2.VideoWriter("out.mp4", cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
frames_written = 0
every_nth = 2
for frame_num in count(0):
ret, frame = in_video.read()
if not ret: # out of frames
break
if frame_num % every_nth == 0:
out_video.write(frame)
frames_written += 1
print(f"{frames_written=}")
Do you know a library in Python to add a frame image to an existing video? The result video must have the same quality as the image.
I tried to use OpenCV to add google image: https://www.google.com/search?q=google&sxsrf=ALiCzsZhrdoHnOTmg0We4dxtguCqzma5Jg:1657603343101&source=lnms&tbm=isch&sa=X&ved=2ahUKEwiTh8bTzfL4AhWhplYBHfXNAKwQ_AUoAXoECAIQAw&biw=1492&bih=739&dpr=1.25#imgrc=PRtenhDnrVrfOM
But the quality decreases when the video elongates.
Here is the final result video : https://drive.google.com/file/d/1ArDvoX-kN9H_oLbACk3kU1Cid93SMczC/view?usp=sharing
Here is my code using OpenCV:
image = cv2.imread(path_image)
height, width, dimensions = image.shape
video = cv2.VideoCapture(path_video)
frames = []
while(True):
ret, frame = video.read()
if ret == True:
frames.append(frame)
# frame = frame.resize(frame, (width, height), fx=0, fy=0, interpolation = cv2.INTER_CUBIC)
# Press S on keyboard
# to stop the process
if cv2.waitKey(1) & 0xFF == ord('s'):
break
# Break the loop
else:
break
video2 = cv2.VideoWriter(path_video,cv2.VideoWriter_fourcc('M','J','P','G'), 30, (width, height))
for frame in frames:
video2.write(frame)
video2.write(image)
video2.release() # releasing the video generated
print("Added {}".format(image_name))
I hope to improve the quality of this video.
I guess a simple way to achieve that using moviepy would be the following:
from moviepy.editor import *
from PIL import Image
import numpy as np
maxsize = (target_width, target_height)
jpg_image = Image.open(path_to_the_image)
# modify the image's resolution to be the target one
jpg_image.thumbnail(maxsize, Image.ANTIALIAS)
jpg_image = np.array(jpg_image)
image = ImageClip(jpg_image).set_duration(target_duration)
clip = VideoFileClip(path_to_the_video)
video = concatenate([image, clip], method="compose")
video.write_videofile("output_example.mp4", fps=target_fps)
As long as you set the target resolution of the image to match the video's one you are set with just that.
So Im trying to make my webcam capture motion, and I how to register motion is going fine but with all these nested while loops my save files are dragged to 30 min long and not 10 sec like intended. I can't figure out what Im doing wrong.
What I mean by dragged out is that I record for 10 sec, but when I go into my files to review the footage it's 30 mins of just some frames.
The idea is to make it register motion and then record for 10 seconds and save the recording as a .avi file.
import cv2
from datetime import datetime
import time
vid_capture = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
ret, cur_frame = vid_capture.read()
prev_frame = cur_frame
capture_duration = 10
motion = False
while True:
frame_diff = cv2.absdiff(cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY), cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY))
if frame_diff.max() > 150:
motion = True
if motion:
start_time = time.time()
name = str(datetime.now().date()) + "_" + str(datetime.now().time().hour) + "-" + str(datetime.now().time().minute) + "-" + str(datetime.now().time().second) + ".avi"
out = cv2.VideoWriter(name, fourcc, 20.0, (640,480))
ret, cur_frame = vid_capture.read()
while time.time() - start_time < capture_duration:
if ret:
out.write(cur_frame)
cv2.imshow('Input', cur_frame)
else:
break
out.release()
cv2.destroyAllWindows()
motion = False
prev_frame = cur_frame.copy()
ret, cur_frame = vid_capture.read()
if cv2.waitKey(1) == 27:
break
vid_capture.release()
Your code may run very fast and it may create ie. 100 frames every second.
But 20.0 in VideoWriter doesn't write it video with speed 20 frames per second but it only inform players that they have to display 20 frames per second. But if you create 100 frames per second so finally it wll need 5 seconds instead of 1 second to display it (100frames/20FPS = 5seconds).
You have to slow down to create new frame every 50ms - (1000ms/20FPS) - you can try waitKey(50).
EDIT:
Because code may need some time to create frame so it may need little smaller dealy in waitKey - i.e. 48 - or you may try to measure time inside loop and use
waitKey( 50 - (loop_end-loop_start) )
You run inner while-loop which all time write the same frame - you should use ret, cur_frame = vid_capture.read() inside this while-loop
Shorter:
name = datetime.now().strftime("%Y-%m-%d_%H-%M-%S.avi")
motion = (frame_diff.max() > 150)
I see one possible problem: cv2.waitKey not work when window is closed - because system sends keys/mouse events only to active window, and when window is closed then cv2 may not get keys/mouse events.
from datetime import datetime
import time
import cv2
vid_capture = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
ret, cur_frame = vid_capture.read()
prev_frame = cur_frame
capture_duration = 10
while True:
frame_diff = cv2.absdiff(cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY), cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY))
motion = (frame_diff.max() > 150)
if motion:
name = datetime.now().strftime("%Y-%m-%d_%H-%M-%S.avi")
print(name)
out = cv2.VideoWriter(name, fourcc, 20.0, (640,480))
start_time = time.time()
while time.time() - start_time <= capture_duration:
ret, cur_frame = vid_capture.read()
if ret:
out.write(cur_frame)
cv2.imshow(name, cur_frame)
if cv2.waitKey(50) == 27:
break
else:
break
out.release()
cv2.destroyAllWindows()
prev_frame = cur_frame.copy()
ret, cur_frame = vid_capture.read()
if cv2.waitKey(1) == 27:
break
vid_capture.release()
Guys I am having problem on overlaying my video to webcam. I can open webcam without any issues or errors but my video is not being showed. I am trying to play my video in specific x-y coordinates.I take most of my code from an other stackoverflow question but I cannot find it know so that I cannot mention it here.
So can someone help me to solve this? Why my video is not being played in my webcam?
I have following code:
from os.path import sep
import cv2 as cv2
# load the overlay image. size should be smaller than video frame size
img = cv2.VideoCapture('photos' + sep + 'Baslksz-3.mp4')
# Get Image dimensions
width = img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
height = img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
# Start Capture
cap = cv2.VideoCapture(0)
cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
frame_vid = img.read()
# Decide X,Y location of overlay image inside video frame.
# following should be valid:
# * image dimensions must be smaller than frame dimensions
# * x+img_width <= frame_width
# * y+img_height <= frame_height
# otherwise you can resize image as part of your code if required
x = 50
y = 50
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# add image to frame
frame[ y:y+width , x:x+height ] = img
'''
tr = 0.3 # transparency between 0-1, show camera if 0
frame = ((1-tr) * frame.astype(np.float) + tr * frame_vid.astype(np.float)).astype(np.uint8)
'''
# Display the resulting frame
cv2.imshow('frame',frame)
# Exit if ESC key is pressed
if cv2.waitKey(20) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()
Let me start analyzing the code step-by-step.
Step #1
img = cv2.VideoCapture('photos' + sep + 'Baslksz-3.mp4')
The above code look fine, but it would be better if you give as a string name
video_name = 'photos' + sep + 'Baslksz-3.mp4'
img = cv2.VideoCapture(video_name)
Step #2
# Get Image dimensions
width = img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
height = img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
Now what are width and height variables?
# Get Image dimensions
width = img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
height = img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
print(width)
print(height)
Result is:
False
False
It seems you want to set width and height to the dimension (150, 150). It would be better if you initialize them separately
# Get Image dimensions
img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
width = 150
height = 150
Step #3
# Start Capture
cap = cv2.VideoCapture(0)
cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
Why do you initialize cap variable two-times?
Step #4
frame_vid = img.read()
Why do you initialize frame_vid you did not use anywhere in the code?
Step #5
while (True):
# Capture frame-by-frame
ret, frame = cap.read()
frame[y:y + width, x:x + height] = img
The above code is not making any sense, you want to display your video as long as your webcam open. You also did not check whether the current webcam frame returns or not. You also set VideoCapture variable to the array?
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
Now you are getting frames, as long as your webcam is open, then you need to check whether the webcam frame returns. If the webcam frame returns then you need to start reading the video frames. If the video frame returns successfully resize the video frame to (width, height) then set it to the frame.
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
if ret:
ret_video, frame_video = img.read()
if ret_video:
# add image to frame
frame_video = cv2.resize(frame_video, (width, height))
frame[y:y + width, x:x + height] = frame_video
Step #6
Make sure close img variable after the execution.
img.release()
cap.release()
cv2.destroyAllWindows()
Please change img variable to something that makes sense. Like rename the img variable to video_capture and cap to the webcam_capture.
When video stops then webcam stacks. But I want to continue infinitive. and video should start again. But video does not starts from beggining.and webcam freezes
Update
This issue was mentioned in the Playback loop option in OpenCV videos
If you look at the answer, the problem was solved by counting the video frames. When video frames equal to the capture frame count (CAP_PROP_FRAME_COUNT) set to counter and CAP_PROP_FRAME_COUNT to 0.
First initialize the frame counter.
video_frame_counter = 0
and when webcam opens, get the frame. If frame returns, increase the counter by 1.
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
if ret:
ret_video, frame_video = img.read()
video_frame_counter += 1
If counter equals to the capture class frame count, then initialize both variable to 0.
if video_frame_counter == img.get(cv2.CAP_PROP_FRAME_COUNT):
video_frame_counter = 0
img.set(cv2.CAP_PROP_POS_FRAMES, 0)
Code:
from os.path import sep
import cv2 as cv2
# load the overlay image. size should be smaller than video frame size
# img = cv2.VideoCapture('photos' + sep + 'Baslksz-3.mp4')
video_name = 'photos' + sep + 'Baslksz-3.mp4'
img = cv2.VideoCapture(video_name)
# Get Image dimensions
img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
width = 150
height = 150
# Start Capture
cap = cv2.VideoCapture(0)
# cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
# frame_vid = img.read()
# Decide X,Y location of overlay image inside video frame.
# following should be valid:
# * image dimensions must be smaller than frame dimensions
# * x+img_width <= frame_width
# * y+img_height <= frame_height
# otherwise you can resize image as part of your code if required
x = 50
y = 50
video_frame_counter = 0
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
if ret:
ret_video, frame_video = img.read()
video_frame_counter += 1
if video_frame_counter == img.get(cv2.CAP_PROP_FRAME_COUNT):
video_frame_counter = 0
img.set(cv2.CAP_PROP_POS_FRAMES, 0)
if ret_video:
# add image to frame
frame_video = cv2.resize(frame_video, (width, height))
frame[y:y + width, x:x + height] = frame_video
'''
tr = 0.3 # transparency between 0-1, show camera if 0
frame = ((1-tr) * frame.astype(np.float) + tr * frame_vid.astype(np.float)).astype(np.uint8)
'''
# Display the resulting frame
cv2.imshow('frame', frame)
# Exit if ESC key is pressed
if cv2.waitKey(1) & 0xFF == 27:
break
img.release()
cap.release()
cv2.destroyAllWindows()
I capture video from my camera, but when i save this i received very fast video. Can i capture video with original frame rate?
import cv2
import time
# exit(1)
cap = cv2.VideoCapture("rtsp://192.168.0.66/live1.sdp")
ps = cap.get(cv2.CAP_PROP_FPS)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # float
# Get current height of frame
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # float
fourcc = cv2.VideoWriter_fourcc(*'XVID')
FILE_OUTPUT = 'out.avi'
FPS = 20.0
cap.set(cv2.CAP_PROP_FPS, FPS)
out = cv2.VideoWriter(FILE_OUTPUT, fourcc, FPS, (int(width), int(height)))
while (True):
ret, frame = cap.read()
if ret == True:
# Write the frame into the file 'output.avi'
out.write(frame)
# Display the resulting frame
cv2.imshow('frame', frame)
# cv2.waitKey(100)
# Press Q on keyboard to stop recording
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Break the loop
else:
break
# When everything done, release the video capture and video write objects
cap.release()
out.release()
# Closes all the frames
cv2.destroyAllWindows()
P.S i use opencv 4 and python3. I try change waitKey option but it had no effect