How to export video as .mp4 using openCV? - python

I am trying to export video as .mp4 with openCV. I have tried several codecs but for now I had no success.
This is a function that constructs a video from frames:
def create_movie(self, out_directory, fps, total_frames):
img1 = cv2.imread("temp/scr0.png")
height, width, layers = img1.shape
codec = cv2.cv.CV_FOURCC('X','V','I','D')
video = cv2.VideoWriter(out_directory, codec, fps, (width, height))
for i in range(total_frames):
img_name = "temp/scr" + str(i) + ".png"
img = cv2.imread(img_name)
video.write(img)
video.release()
cv2.destroyAllWindows()
I usually get next error message, using different codecs:
Tag XVID/0x44495658 incompatible with output codec id '13'
Is is possible to do this and how?

There is a non-direct solution. You export as .avi and then convert to .mp4 using python's call which calls terminal command.
from subprocess import call
dir = out_directory.strip(".avi")
command = "avconv -i %s.avi -c:v libx264 -c:a copy %s.mp4" % (dir, dir)
call(command.split())

May be a little bit late to answer this, but if you want to write an .MP4 file with OpenCV try this:
import cv2
#your previous code here
fourcc = cv2.VideoWriter_fourcc(*'a\0\0\0')
out = cv2.VideoWriter('out.mp4', fourcc, fps, res)
#the character '\0' is the Null-Terminator or simply 0x00 in the ASCII-Table
#tag: *'a\0\0\0' corresponds to 0x00000061
#your following code here

Related

Read video from base64 in python

I would like to process a video that I receive through an upload component in plotly dash. Currently I am creating a tempfile and then reading the video with opencv. However, I would like to avoid writing the file to disk. Is there a way to process the video directly from memory? My code looks like this:
def process_motion(contents, filename):
print("Processing video: " + filename)
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
with tempfile.NamedTemporaryFile() as temp:
temp.write(decoded)
cap = cv2.VideoCapture(temp.name)
frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
fps = cap.get(cv2.CAP_PROP_FPS)
# some calculations
Interesting question
as #Dan MaĊĦek has correctly mentioned, the correct keyword to search would be video decoding. The thing is, like OpenCV, must of decoding libraries in python using FFMPEG as the backend and most of them are wrappers around the FFMPEG executable (run FFMPEG in subprocess), and since FFMPEG accepts file path for decoding (or URL for decoding video stream) those wrappers also accept file path.
AFAIK, the only wrapper library which accepts bytes as input to decode video and get all frames is imageio which behind the scene also converts bytes to a temp file and decode it using FFMPEG.
Here is the comparison of using imageio and your solution.
import base64
import imageio.v3 as iio
import cv2
from time import perf_counter
import tempfile
import numpy as np
with open("example.mp4", "rb") as videoFile:
base_text = base64.b64encode(videoFile.read())
buffer = base64.b64decode(base_text)
start = perf_counter()
frames = iio.imread(buffer, index=None, format_hint=".mp4")
print("iio ffmpeg pluing: ", perf_counter() - start)
print(frames.shape)
start = perf_counter()
frames = iio.imread(buffer, index=None, plugin="pyav", format_hint=".mp4")
print("iio pyav pluing: ", perf_counter() - start)
print(frames.shape)
start = perf_counter()
with tempfile.NamedTemporaryFile() as temp:
temp.write(buffer)
cap = cv2.VideoCapture(temp.name)
frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
fps = cap.get(cv2.CAP_PROP_FPS)
success, frame = cap.read()
frames = [frame]
while success:
success, frame = cap.read()
frames.append(frame)
frames = np.stack(frames[:-1])
print("cv2: ", perf_counter() - start)
print(frames.shape)
============================================
iio ffmpeg pluing: 0.3905044999992242
(901, 270, 480, 3)
No accelerated colorspace conversion found from yuv420p to rgb24.
iio pyav pluing: 0.3710011249931995
(901, 270, 480, 3)
cv2: 0.2388888749992475
(901, 270, 480, 3)
Note: if you are able to create a python wrapper for FFMPEG it is possible to convert a bytes array to a format that is acceptable FFMPEG's stream decoding function. as explained here

Opencv videowriter doesn't save video on flask

i'm trying to save the output video.mp4 file to my dirc. it works individually, so i think my code is not wrong...
but when i use the function on app.py. the terminal is showing, it is processing. but i can't get actual video.mp4 file.
what is the problem of this?
this is original source function what i'm trying
def video():
pathIn=''
pathOut = ''
fps = 10
frame_array = []
files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))]
#for sorting the file names properly
files.sort(key = lambda x: x[5:-4])
files.sort()
----------
for i in range(len(files)):
filename=pathIn + files[i]
#reading each files
img = cv2.imread(filename)
height, width, layers = img.shape
size = (width,height)
#inserting the frames into an image array
frame_array.append(img)
out = cv2.VideoWriter(pathOut,cv2.VideoWriter_fourcc(*'avc1'), fps, size)
for i in range(len(frame_array)):
# writing to a image array
out.write(frame_array[i])
i tried individually the code and searched a lot about flask.
another function from other py is working well on flask. but only this opencv is not working.
from make_vid import video
#app.route('/upload_gpx', methods=["GET", "POST"])
def upload_gpx():
video()
return render_template('public/display_vid.html')
and my terminal shows
OpenH264 Video Codec provided by Cisco Systems, Inc.
this. so i think the video() is worked but i can't get my video.
only when i run the makevid.py, i can get my video.
i need help that how can i get the video using video() function on flask??

The document could not be opened, opencv python3

I'm trying to make a video from images with python and OpenCV but when I run the script the video is generated but when I try to open it I give this error:
This is the script:
import cv2
import numpy as np
import glob
frameSize = (1920, 1080)
out = cv2.VideoWriter('output_video.avi',cv2.VideoWriter_fourcc(*'DIVX'), 60, frameSize)
for filename in glob.glob('/folder_path/*.jpg'):
img = cv2.imread(filename)
out.write(img)
out.release()
UPDATE:
If I use
out = cv2.VideoWriter('output_video.avi',cv2.VideoWriter_fourcc(*'MJPG'), 60, frameSize)
Instead
out = cv2.VideoWriter('output_video.avi',cv2.VideoWriter_fourcc(*'DIVX'), 60, frameSize)
The video start but I can see anything
Ok, I have found a solution.
This is the final code:
import cv2,os
from os.path import isfile, join
def convert_pictures_to_video(pathIn, pathOut, fps, time):
# this function converts images to video
frame_array=[]
files=[f for f in os.listdir(pathIn) if isfile(join(pathIn,f))]
#files.remove(".DS_Store")
for i in range (len(files)):
filename=pathIn+files[i]
# reading images
img=cv2.imread(filename)
# img=cv2.resize(img,(1400,1000))
height, width, layers = img.shape
size=(width,height)
for k in range (time):
frame_array.append(img)
out=cv2.VideoWriter(pathOut,cv2.VideoWriter_fourcc(*'mp4v'), fps, size)
for i in range(len(frame_array)):
out.write(frame_array[i])
out.release()
pathIn= '/pathIn-folder/'
pathOut='/pathOut-folder/output.avi'
fps=1
time=20 # the duration of each picture in the video
convert_pictures_to_video(pathIn, pathOut, fps, time)
You can find more info and a tutorial here.
REMEMBER
If you have a mac there are two important things to do.
First you have to uncomment #files.remove(".DS_Store") because when you create a new folder on macOS there is an extra hidden file called .DS_Store
You can't open the output video with Quick Time Player
You have to use another software like VLC

Which OpenCV FOURCC codecs should I use for my Python program?

I have implemented a Python script which displays a video to the user and records it. The video is saved either compressed or uncompressed.
In an old program I have seen, that the "DIVX" MPEG-4 and the "IYUV" codecs were used. For some reason, they don't work on my computer (OUTPUT_VIDEO is a MP4-file).
OpenCV: FFMPEG: tag 0x58564944/'DIVX' is not supported with codec id 13 and format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV: FFMPEG: fallback to use tag 0x00000020/' ???'
The "MPJPG" codec works with ".avi" files.
Because I'm not sure about the codecs, I would like to ask, which codecs should I use for my script to achieve the following requirements:
the video sequence can be saved as .mp3, .mp4 file (both compressed) or as .avi file (uncompressed).
Python script should work on Windows and Linux platforms.
This is my source code:
main.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import cv2
import platform
#=========== TO CHANGE ===========
INPUT_VIDEO = os.path.join("..", "resources", "video.mp4")
OUTPUT_VIDEO = os.path.join("..", "recorded", "recorded.avi")
compress = False
#=========== TO CHANGE ===========
WINDOW_NAME = "Video Recorder"
player = cv2.VideoCapture(INPUT_VIDEO)
# Get the frames per second (fps) of the video.
fps = player.get(cv2.CAP_PROP_FPS)
# Get width and height via the video capture property.
width = player.get(cv2.CAP_PROP_FRAME_WIDTH)
height = player.get(cv2.CAP_PROP_FRAME_HEIGHT)
# Define the codec and create VideoWriter object according to the used operating system.
four_cc = None
if platform.system() == "Windows":
if compress:
four_cc = cv2.VideoWriter_fourcc(*"MJPG") # *"DIVX") # DIVX MPEG-4 codec.
else:
four_cc = cv2.VideoWriter_fourcc(*"MJPG") # *"IYUV") # Uncompressed yuv420p in avi container.
elif platform.system() == "Linux":
if compress:
four_cc = cv2.VideoWriter_fourcc(*"DIVX") # DIVX MPEG-4 codec.
else:
four_cc = cv2.VideoWriter_fourcc(*"IYUV") # Uncompressed yuv420p in avi container.
recorder = cv2.VideoWriter(OUTPUT_VIDEO, four_cc, fps, (int(width), int(height)))
if player is None:
quit()
while player.isOpened():
ret, frame = player.read()
if ret:
cv2.imshow(WINDOW_NAME, frame)
recorder.write(frame)
else:
break
key_code = cv2.waitKey(1)
# Closes the window if the ESC key was pressed.
if key_code == 27:
break
# Closes the window if the X button of the window was clicked.
if cv2.getWindowProperty(WINDOW_NAME, 1) == -1:
break
player.release()
recorder.release()
cv2.destroyAllWindows()
I'm using a Windows 7 computer, with opencv-contrib-python 3.4.0.12 and Python 3.6.

Cannot Demultiplex Stream from Video created by Py OpenCV

I'm trying to use OpenCV to create a video out of individual frames. Although the code runs without error, I cannot play the resulting avi file. When I do, the error I get is Could not demultiplex stream.
The stripped down version of the code I'm using to do this is:
import caffe
import cv2
import fnmatch
import os
# Get Image List
image_list = fnmatch.filter('./sample/images','*.png')
image_list.sort()
# Create VideoWriter
# codec = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
# codec = -1
codec = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
video = cv2.VideoWriter( './movieT.avi',
codec,
20,
(289, 289))
for img_name in image_list:
# Load image
im_path = os.path.join('./sample/images',img_name)
img = caffe.io.load_image(im_path)
# Resize image to expected size
img = caffe.io.resize(img,(289, 289, 3))
# Write image
video.write(img)
video.release()
I Googled around a bit, and the main errors I see mentioned are ensuring the image sizes match the size expected by the cv2.VideoWiter and that I have the right codecs. I resize my images to ensure they are the right size and I tried a few different codecs. I also tried to install standard codecs using some apt-get install commands I also found by Googling around:
me#balin:~$ sudo apt update
me#balin:~$ sudo apt install libdvdnav4 libdvdread4 gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly libdvd-pkg
me#balin:~$ sudo apt install ubuntu-restricted-extras
I am currently using:
Ubuntu 18.04
Python 2.7.17
cv2.__version__ 4.0.1
I think your problem in incorrect use of fnmatch.filter() which doesn't get filenames from folder but it is used only to check if filename match pattern.
See example from fnmatch
import fnmatch
import os
for file in os.listdir('.'):
if fnmatch.fnmatch(file, '*.txt'):
print(file)
With your code I alwyas get empty list so later it can't add any image to video and I can't display this video.
But you can use glob.glob() for this
image_list = glob.glob('./sample/images/*.png')
This code works for me
import cv2
import glob
image_list = glob.glob('./sample/images/*.png')
image_list.sort()
#print(image_list)
codec = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
video = cv2.VideoWriter('./movieT.avi', codec, 20, (289, 289))
for img_name in image_list:
img = cv2.imread(img_name)
img = cv2.resize(img, (289, 289))
video.write(img)
video.release()

Categories