Python cv2 outputs invalid video - python

System information
OpenCV => 4.4.0.46
Operating System / Platform => MacOS Catalina 10.15.4
Compiler => Jupyter Notebook via Anaconda 4.8.3
I'm doing a computer vision task, in which my current step is to create a video based on previously created images. To do so, I'm using OpenCV like this:
fps = 25
files = natsorted([f for f in glob.glob(os.getcwd()+'/tf_files/test/*.jpg')])[:125]
size = (1920,1080)
fourcc = int(cv2.VideoWriter_fourcc(*'mp4v'))
out = cv2.VideoWriter('test.mp4',fourcc,fps=fps,frameSize=size)
for file in files:
img = cv2.imread(file)
out.write(img)
out.release()
cv2.destroyAllWindows()
The files list returns the paths of the images:
files[0]
'/Users/XXX/XXX/projects/phase_seg/tensorflow-for-poets-2/tf_files/test/0.jpg'
with the size of each file being:
cv2.imread(files[0]).shape
>>> (1080, 1920, 3)
The code does not give any errors and does actually create a video called 'test.mp4'. Moreover, if the amount of images is changed, the video does change in size as well. I can also open the images with opencv without any problem.
However, the video cannot be played, and when exported to another program, it is of length 0. I've tried different variations of fourcc like 'M','P','4','V', but without any success. What can be a possible explanation for this?

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.

Why is the last frame always excluded, when converting images into a video?

I have a folder with 225 pictures of maps. So, I compiled it to an mp4 file using imageio. Whether it's compiling 10 maps, 150, or all 225, the last picture is always not included in the video.
import os
from natsort import humansorted
import imageio
os.chdir(r'folder/path/')
filenames = humansorted((fn for fn in os.listdir('.') if fn.endswith('.png')))
with imageio.get_writer('earthquake_video.mp4', mode='I', fps=2) as writer:
for filename in filenames:
image = imageio.imread(filename)
writer.append_data(image)
writer.close()
For me, your code works fine for 10, 150, or even 225 images – as long as I open the resulting video in Windows Media Player. If I open the video in VLC media player, I get distorted playback, not only skipping the last frame. (I have numbers counting from 0 to 224, so every mistaken frame is noticed.) So, if you use VLC media player, your problem most likely is the one discussed in this StackOverflow Q&A.
On the imageio GitHub issue tracker, there's also this issue, linking to this other StackOverflow question, which seems to be same issue as you have. But, still, I think it's the afore-mentioned issue with the VLC media player.
Unfortunately, I couldn't get the workaround from the first linked Q&A working using the output_params from imageio, i.e. setting -framerate or -r. So, my workaround here would be to set up a desired fps (here: 2), and a fps for the actual playback (in VLC media player), e.g. 30, and then simply add as many identical frames as needed to fake the desired fps, i.e. 30 // 2 = 15 here.
Here's some code:
import os
import imageio
os.chdir(r'folder/path')
filenames = [fn for fn in os.listdir('.') if fn.endswith('.png')]
fps = 2 # Desired, "real" frames per second
fps_vlc = 30 # Frames per second needed for proper playback in VLC
with imageio.get_writer('earthquake_video.mp4', fps=fps_vlc) as writer:
for filename in filenames:
image = imageio.imread(filename)
for i in range(fps_vlc // fps):
writer.append_data(image)
writer.close()
The resulting video "looks" the same as before (in Windows Media player), but now, it's also properly played in VLC media player.
Even, if that's not YOUR actual problem, I guess this information will help other coming across your question, but actually suffering from the stated issue with the VLC media player.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.9.1
PyCharm: 2021.1.1
imageio: 2.9.0
----------------------------------------

Python OpenCV - CascadeClassifier Haarcascade detectMultiScale() not working

I am learning OpenCV through Python v3.8.5 since last few days, got stuck in CascadeClassifier on Facedetection. Following the same code as the tutor : https://www.youtube.com/watch?v=LopYA64KmdE Timestamp: 08:40
I have the image and haarcascade_frontalface_default.xml files in the resources folder
Still, I don't get any output for this below code. I tried changing images files too but still no output. When I tried printing it print till 'foo1'. So I suspect the issue is around detectMultiScale() method.
Here is my code:
import cv2
face_cascade = cv2.CascadeClassifier('resources\haarcascade_frontalface_default.xml')
# img = cv2.imread('resources\\lena.jpg')
# img = cv2.imread('D:\photos\house\DSCF2736 copy.jpg')
img = cv2.imread('resources\\messi5.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
print('foo1')
faces = face_cascade.detectMultiScale(gray,1.1,4)
print('foo2')
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+h,y+w),(0,255,0),2)
cv2.imshow('out',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
I am using Windows7 32 bit PC. Is this due to OS support issue? Please let me know the solution.
Thanks
I guess you should write [x,y,w,h,] or (x,y,w,h) instead of x,y,w,h in the for loop because the given detectMultiScale function generates a list containing multiple [x,y,w,h] elements for every face and lists can be stored only in lists objects or tuples.
It's in the resources folder, but is the current working directory properly set relative to the calling script. There's a common issue when the path to this xml file is not properly set for one or another reason - try with absolute path or copy it in the folder with the script and calling from command line in that folder.
See:
OpenCV Facial Detection come ups with this error

How to save a picture to a specific file after using OpenCV to take it?

I use Python 3 and Windows. Currently, all my program can do is take a picture and display it, but I want to be able to save it to a specific destination. Here is the program:
# import the opencv and numpy libraries
import cv2
import numpy as np
# define a video capture object
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
while(True):
cv2.imshow('img1',frame)
if(cv2.waitKey(1) and 0xFF == ord('y')):
cv2.imwrite('images/c1.png', frame)
cv2.destroyAllWindows()
break
cap.release()
Edit: BTW I'm new to Python and OpenCV so this code is mostly someone else's (forgot who so I can't cite, sorry).
You are currently writing the image to a file 'images/c1.png'. You can change this to an absolute path where you want to save the image i.e. C:/Users/User/Pictures/c1.png or you can set the current working directory to a different folder with os.chdir('desired location') so that it saves all images to that particular location (in this case it will save the image as 'images/c1.png' in that location).

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