python - Output by OpenCV VideoWriter empty - python

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.

Related

Python cv2.VideoCapture() has wrong resolution and read cropped images

I'm trying to read images from an IDS GV-5240CP camera plugged to my laptop via ethernet using Python and OpenCV.
This is what I am supposed to get :
A 1280x1024 image (here resized for upload)
But using this code:
import cv2
cap = cv2.VideoCapture(1)
_, frame = cap.read()
print(frame.shape)
cv2.imshow("Out", frame)
cv2.waitKey(2000)
cap.release()
cv2.destroyAllWindows()
cv2.imwrite('Test2.png', frame)
I get:
A 640x480 cropped image
How can I set my video capture to the native resolution?
VideoCapture uses 640x480 by default.
If you want a different resolution, specify it in the constructor or use the set() method with CAP_PROP_FRAME_WIDTH and so on. Details in the docs.
cap = cv2.VideoCapture(1, apiPreference=cv2.CAP_ANY, params=[
cv2.CAP_PROP_FRAME_WIDTH, 1280,
cv2.CAP_PROP_FRAME_HEIGHT, 1024])
out = cv2.VideoWriter(("E:", 'output.avi'), fourcc, 20.0, (640, 480))
try using this and change the resolution according to your need,
tho it will download or use
cv2.resize(frame,(w,h),fx=0,fy=0, interpolation = cv2.INTER_CUBIC)
since you don't want to do this then use set() module in OpenCV to set specific resolution. docs.opencv.org/4.x/d8/dfe/… this link for the full info about set()

OpenCV VideoWriter writes corrupted video files

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.

Why different color between skimage.io.imsave and opencv.VideoWriter

I'm trying to make opencv VideoWriter to generate avi from images modified by skimage-kit. And I encountered color difference between skimage.io.imsave and VideoWriter.write".
When I see the movie generated by opencv,it looks having only blue. However, if I save the frame by skimage.io.imsave, the jpg file has correct colors.
I assume normalization happens in skimage causes something bad to me but I'm not sure how I can convert them to collect color for opencv.
Can anyone advice why the difference comes from and how I should solve it?
I really appreciate any advice.
result of imsave,which I want
result of output.avi
import numpy
import cv2
from colorizer import Colorizer #returns modified 224*224 color image using skimage kit
import skimage
c=Colorizer()
cap = cv2.VideoCapture('test.mp4')
fourcc = cv2.cv.CV_FOURCC(*'MJPG')
out = cv2.VideoWriter('output.avi',fourcc, 12.0, (224,224))
i=0
while(cap.isOpened()):
ret, frame = cap.read()
cframe=c.colorize(frame)
#it outputs correct color image
skimage.io.imsave("result/%d.jpg" % i, cframe)
#it outputs wrong color
out.write(skimage.img_as_ubyte(cframe))
i=i+1
cap.release()
out.release()
cv2.destroyAllWindows()
Thanks ZdaR. With your advice, I simply transpose matrix RGB to BGR, then it worked!
Higher version of opencv may have cvcolor RGB2BGR but my enviroment doesn't support it thus I implement in legacy way..
cframe=c.colorize(frame)
img=np.zeros((224,224,3),dtype=np.float32)
img[:,:,0]=cframe[:,:,2]
img[:,:,1]=cframe[:,:,1]
img[:,:,2]=cframe[:,:,0]
out.write((img*225.0).astype('u1'))

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