OpenCV VideoWriter writes corrupted video files - python

I am trying to stream and save video from my webcam with the Python script shown below but, for some reason, the 'myvideo.mp4' file has a very small size and cannot be opened with QuickTime (or other players) - it seems to be empty. However, the video stream works perfectly.
As suggested in other topics, I have tried different file formats and codecs and I pass exact fps, width and height that my webcam returns. Perhaps anyone knows what can be the issue here? Thanks in advance!
import cv2
cap = cv2.VideoCapture(0)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
fps = cap.get(cv2.CAP_PROP_FPS)
writer = cv2.VideoWriter('myvideo.mp4',cv2.VideoWriter_fourcc(*'mp4v'),fps,(width,height))
while True:
ret,frame = cap.read()
# OPERATIONS (DRAWING)
writer.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
writer.release()
cv2.destroyAllWindows()
I have also tried running the script as superuser but it did not help. I am using Mac.
QuickTime error:
The document “myvideo.mp4” could not be opened.
The file isn’t compatible with QuickTime Player.

Try to change fourcc(4-character code of codec used to compress the frames.)
writer = cv2.VideoWriter('myvideo.mp4',cv2.VideoWriter_fourcc(*'mp4v'),fps,(width,height))
replace it with
writer = cv2.VideoWriter('myvideo.mp4',cv2.VideoWriter_fourcc(*'XVID'),fps,(width,height))

Simply fix typo
Change
height = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
to
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
You were taking CAP_PROP_FRAME_WIDTH twice.
If the problem persists...
If this still does not help, try to swap them. It seems stupid, but helped for me. I guess that the get method somehow takes orientation into account, but then reading a frame neglects the orientation of the video (or opposite, does not matter, they are just inconsistent). I had exactly the same problem, and swapped width with height and it solved it.
Extra
A bit old list of codecs tested on mac.

Related

Cannot view video after writing in python/OpenCV

Edit: The problem was fixed after using VLC media player. The standard windows media player could not read the videos.
I am attempting to take a video, run it through an object detector, add the bounding boxes, and output the video with the bounding boxes. However, I'm having a strange problem where the video I output cannot be viewed. I get a "Server execution failed" error when attempting to play the video on my local windows 10 machine. I am developing through SSH on ubuntu 20.04 with the vs code remote development extension.
Here is some OpenCV code that does not work with my setup. The video is written to the disk, and OpenCV is able to read frames from output5.avi, however the output5.avi file cannot be opened as I described.
import cv2
cap = cv2.VideoCapture("video.mov")
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
out = cv2.VideoWriter('output5.avi', fourcc, 30, (width, height), isColor=True)
while cap.isOpened():
# get validity boolean and current frame
ret, frame = cap.read()
# if valid tag is false, loop back to start
if not ret:
break
else:
frame = cv2.resize(frame, (width, height))
out.write(frame)
cap.release()
out.release()
I have also attempted to save the video through torchvision.io.write_video, but the exact same problem occurs. Tensorboard similarly doesn't work.
It must be something wrong with how the remote machine is set up, but I have no idea what could be wrong.

python - Output by OpenCV VideoWriter empty

I have recently started to program with opencv-python, but I got stuck when I tried to write a video using cv2. The output by the script is empty. Here's my code:
import cv2
import numpy as np
import matplotlib.pyplot as plt
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'h263')
out = cv2.VideoWriter('cv2_camera_output.mp4',fourcc, 20.0, (800,600))
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', frame)
cv2.imshow('gray', gray)
out.write(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
I guessed that the issue must have something to do with the fourcc codec. So I googled if there was a fourCC codec for mac (I am using OS X 10.12.3 (Sierra)), but all the suggestions didn't work for my computer, so the issue may not even be in the fourCC codec. These are the links I have visited:
OpenCV Documentation (I didn't follow this one, it was just to make sure, and it didn't work either)
GitHub Tests for FourCC codecs on OS X
Does anybody know the real issue? Any help would be great
Your frame width and height must be the same as the width and height of your VideoWriter. Just add this before out.write(frame) and you might be fine:
frame = cv2.resize(frame,(800,600))
Or change the size of your VideoWriter to the initial size of webcam frame. Mine is (640,480). I think if your OS doesn't support the format, it just won't write anything. Not even an empty file will be created. I'm on Linux and I think 'h263' doesn't work on it but 'h264' does. When I use 'h263' it just doesn't make any file.
I solved the problem. The problem simply was that I could not use the VideoWriter for grayscale, so I had to use it for the coloured frame.
Biggest problem is that h263 specifies the exact frame sizes it can encode (take a look at the possible values at https://en.wikipedia.org/wiki/H.263#Version_1_and_Annex_I) and you don't comply with that.
After resolving this issue it is possible that h263 still won't work with mp4 container on OSX (on Linux and Windows it doesn't because they use FFMPEG as backends but OSX uses another library) so I suggest that you use avi as container.
And lastly you will have to either resize your image (just like #ROAR said) or use the dimensions of the input device like this:
width = int(cap.get(3))
height = int(cap.get(4))
Although if you do the latter with h263 codec than you have to use an input device which produces frames that are compliant with the size restrictions.
My problem was actually that I did not have space left on my disk. It not did give a warning.

Why does OpenCV cap.get(cv2.CAP_PROP_POS_MSEC) only return 0?

I have recently installed OpenCV for PYTHON on my mac by following the tutorial:
http://www.pyimagesearch.com/2016/12/19/install-opencv-3-on-macos-with-homebrew-the-easy-way/
I wrote a code to read a videofile, which is able to retrieve the fps,timestamp,total no. of frames, at each frame that is read:
cap = cv2.VideoCapture(particle_name + video_file_type)
while True:
time = cap.get(cv2.CAP_PROP_POS_MSEC)
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
print(time, fps, total_frames)
ret, frame = cap.read()
cv2.imshow('frame', frame)
cap.release()
cv2.destroyAllWindows()
I tried this code out on Video A, .mov format, Motion JPEG Video (dmb1) codec.
And Video B, .avi format, Motion JPEG Video (MJPG) codec.
For both Video A and Video B, the fps and total_frames printed out were constants. However, for Video A, time increased gradually (as it should), but for Video B, time remained constant at 0.
I thought it could be the format of the videos that causes this difference so I changed the format of Video B to .mov while retaining the same codec, however the problem still persisted.
May I know how I can retrieve the accurate timestamp from Video B?
I'm not sure why the cap.get(cv2.CAP_PROP_FRAME_COUNT) isn't returning the correct timestamp. This could be a codec issue. Yoo could try other codecs like XVID, MP4V, etc. Note that the extension merely denotes the container for the file and changing that may not really result in any meaningful change in the video file.
If you still are unable to get it work, use the frame count along with the FPS of the image to get the timestamp.
fps = cap.get(cv2.CV_CAP_PROP_FPS)
frame_count = 0
while True:
frame_count++
time = float(frame_count)/fps
EDIT:
You can change the codec using ffmpeg. Here's a sample tutorial for Macs https://www.macxdvd.com/mac-dvd-video-converter-how-to/ffmpeg-avi-to-mp4-free.htm.

Sending OpenCV2 Videowrite input to buffer instead of file

I would like to write openCV2 videorecorder output to a buffer in the memory rather than to a file on my hard drive. Following that i could write out to a file or not (and this way save a flash based object from over use). I've tried pyfilesystem and i've tried things like IO and StringIO, but VideoRecorder does not accept these saying it was looking for a String or Unicode type and instead found a (_IOTextWrapper, IOString, etc....) type.
I get now what you mean, however that would somehow tend to break the purpose of VideoWriter I suppose. It's job is to write the video on the disk. However, I agree, it would be nice to have a Video class that then we could manipulate within cv2.
Meanwhile, lucky for us, video's are nothing but sequences of frames, which are but numpy arrays. We can do a lot with those so here's the general idea I'd propose:
import numpy as np
import cv2
def save_to_vid(video):
path = ".../output.avi"
height , width , layers = video[0].shape
out = cv2.VideoWriter(path, cv2.cv.FOURCC("X", "V", "I", "D"),
20.0, (width, height))
for frame in frames:
out.write(frame)
out.release()
##CAPTURING SOME TEST FRAMES
cap = cv2.VideoCapture(0)
frames = list() #THIS IS YOUR VIDEO
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame,0)
frames.append(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
#SOMETIMES LATER IN THE RPOGRAM
doYouWantToSave = True
if doYouWantToSave:
save_to_vid(frames)
else:
del frames
Of course this all can be done smarter I suppose by creating your own class Video and then instantiating that and handling it as an object in your code. Video could have a method "writeToFile" as well. It could even be scripted a bit smarter to save some space, or work as an actual buffer if that's exactly what you need.

OpenCV videowrite doesn't write video

I used the following page from OpenCV 3.0.0 tutorial: Tutorial in docs
When I tried to use the example that saves videos, it doesn't work.
It displays the content from the webcam, and also creates a file called output.avi, but when I checked the size of ouput.avi, it was zero bytes.
I also tried using different codecs, like YUY2.
I use Python 2.7.8 and OpenCV 3.0.0
and Windows 8.1
I had the same problem and I solved it by specifying the video output resolution to exactly the same as input:
cap = cv2.VideoCapture('vtest.avi')
...
out = cv2.VideoWriter('output.avi',fourcc, 20.0,(int(cap.get(3)),int(cap.get(4))))
Of course make sure you got ffmpeg installed and working.
Replacing:
fourcc = cv2.VideoWriter_fourcc(*'XVID')
With:
fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
Worked for me...
More generally:
Look up the fourcc code of the video compression format you're after here, and whatever the code is - for instance 'FMP4' for FFMpeg - plug it in in the following manner:
cv2.VideoWriter_fourcc('F','M','P','4')
I was struggling with this problem for a few hours then I realized that I had typed the image's shape wrong.
It is (width, height), ie:
(image.shape[1], image.shape[0])
and not
(image.shape[0], image.shape[1])
This is how my working code looks like finally... (I am on a Windows machine):
video_path = FILENAME + '.avi'
size = images[0].shape[1], images[0].shape[0] ## <<<--- NOTICE THIS
video = cv2.VideoWriter(video_path,cv2.VideoWriter_fourcc(*'DIVX'), 60, size)
for img in images:
video.write(img)
cv2.destroyAllWindows()
video.close()
Make sure you are using the correct fourcc 4-byte code. The example on the tutorial has:
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
This XVID code may only work for linux. The documentation above the example states (in the tutorial):
"In Windows: DIVX (More to be tested and added)." So if you haven't, try replacing the fourcc line above with:
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
I use cv2.VideoWriter on linux quite often and it always works. So if the above doesn't work you can always try it on a linux vm.
In my case, I thought the codec was an obstacle but it wasn't. Instead, adjusting the dimensions being consumed by videoWriter() did the trick:
(ok, frame) = cv2.VideoCapture(videoPath).read()
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(output, fourcc, 10.0, (1280, 720))
(1280,720) was used because frame.shape from my video outputs (1280, 720, 3). It made avi to mp4 and vice versa possible. Didn't have to worry about reconciling the codec.
Check the resolution of your images!
I was trying with odd-shaped images (1284x709) and ended up with unreadable videos of 1k in size. After resizing my image to the closest 'common' resolution:
image = cv2.resize(image, (1280,720)),
it worked just fine.
I suspect there are a lot of reasons video writing fails silently, and in my case, my frame was a composite of a 3 channel image and a 4 channel image (transparent overlay). Converting the end result to BGR format as follows allowed the video to save successfully.
width = 1280
height = 720
FPS = 30
fourcc = VideoWriter_fourcc(*'avc1')
video = VideoWriter('output.mp4', fourcc, float(FPS), (width, height))
for img in images:
frame = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
video.write(frame)
video.release()
It should be a problem with the codec you're using.
Have you tried:
cv.CV_FOURCC('i', 'Y', 'U', 'V')
This one worked for me.
On windows 7 and using Python 2.7 and OpenCV 2.4.8, I experienced the fact that if the file NAME is "output.mpg" would not write.
I solved it by changing to "output.avi".
I have the exact same issue. I am using OpenCV in C++, but I believe you can still pass -1 instead of choosing the codec so you can have a drop down menu of the available codecs even in python. From there I tried all different codecs and just like Leonard Zhou, the IYUV codec was the one that worked for me. Also note that it was the only one that worked even though I could use XVID just fine on another machine with the same code and same codec installer.
EDIT:
What I suggested worked as a patch, the main issue was solved on my end by adding the opencv_ffmpeg dll in the executable's folder.
I changed the Video writer size to my screen resolution size and it worked.
here is the solution.
out = cv2.VideoWriter("output.avi", fourcc, 5.0, (1920, 1080))
It worked for me after I assigned the actual frame size and not what I thought the size was:
ret, frame = cap.read()
height, width, channels = frame.shape
codec = cv2.VideoWriter_fourcc(*"DIVX")
out=cv2.VideoWriter('new.avi',codec ,20.0,(width, height))
And put out.write(frame) inside the while loop before cv2.imshow("Frame", frame).
To state the obvious, make sure you're giving not only a correct path, but also a video name.
i.e. path/'video.avi' and not just path/. It will fail silently otherwise.
I had same issue that the video file was being created without any errors but it won't run and had a size of few KBs. Here's how I resolved it;
Make sure you have passed FPS argument in float value.
The output resolution needs to be same as of input video resolution.
In my case I am resizing the image, but saving video with original size instead of new size.
After trying hours to find the error, I finally found it. So here are some things to keep in mind. (For Linux users particularly)
Use this codec ("MJPG").
cv2.VideoWriter_fourcc(*'MJPG')
Do not forget to write the Boolean value as final argument (True for RGB and False for GrayScale) in
cv2.VideoWriter(path, fourcc, float(frameRate), frameSize, True)
The argument, frameSize required by cv2.VideoWriter is a tuple of form (width, height) and not (height, width) which is the shape of image array if you open the image using cv2.read or Image.open. So don't forget to invert it.
The above methods work only for RGB frames/images. Incase you are trying to write a grayscale image, pass a parameter 0 to the VideoWriter():
fourcc = cv2.VideoWriter_fourcc(*"MJPG")
out = cv2.VideoWriter('output.avi', fourcc, 30, size, 0)
I tried by creating its exe using pyinstaller Recorder.py it worked for me.
Remember before using pyinstaller you have to pip install pyinstaller.

Categories

Resources