using opencv2 write streaming video in python - python

In my project i want to save streaming video.
import cv2;
if __name__ == "__main__":
camera = cv2.VideoCapture(0);
while True:
f,img = camera.read();
cv2.imshow("webcam",img);
if (cv2.waitKey (5) != -1):
break;
`
using above code it is possible to stream video from the web cam. How to write this streaming video to a file?

You can simply save the grabbed frames into images:
camera = cv2.VideoCapture(0)
i = 0
while True:
f,img = camera.read()
cv2.imshow("webcam",img)
if (cv2.waitKey(5) != -1):
break
cv2.imwrite('{0:05d}.jpg'.format(i),img)
i += 1
or to a video like this:
camera = cv2.VideoCapture(0)
video = cv2.VideoWriter('video.avi', -1, 25, (640, 480));
while True:
f,img = camera.read()
video.write(img)
cv2.imshow("webcam",img)
if (cv2.waitKey(5) != -1):
break
video.release()
When creating VideoWriter object, you need to provide several parameters that you can extract from the input stream. A tutorial can be found here.

In ubuntu create video from given pictures using following code
os.system('ffmpeg -f image2 -r 8 -i %05d.bmp -vcodec mpeg4 -y movie3.mp4')
where name of picture is 00000.bmp,00001.bmp,00002.bmp etc..

If you really want to use the codec provided for your pc to compress the frames.
You should set the 2nd parameter of cv2.VideoWriter([filename, fourcc, fps, frameSize[, isColor]]) with the flag value = -1. This will allow you to see a list of codec compress utilized in your pc.
In my case, the codec provided by Intel is named IYUV or I420. I don't know for another manufacturers. fourcc webpage.
Set this information as follow
fourcc = cv2.cv.CV_FOURCC('I','Y','U','V')
# or
fourcc = cv2.cv.CV_FOURCC('I','4','2','0')
# settting all the information
out = cv2.VideoWriter('output1.avi',fourcc, 20, (640,480))
Remember two small parameters which gave me a big headache:
Don't forget the cv2.cv prefix
Introduce the correct frame Size
For everything else, you can use the code provided by Ekalic

Related

Saving OpenCV output in Motion JPEG format. Getting a "'MJPG' is not supported with codec id 7" error

I'd like to save video camera output in motion JPEG (MJPG) format. The below code,
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
if (cap.isOpened() == False):
print("Unable to read camera feed")
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
frame_per_sec = int('10')
out = cv2.VideoWriter('output.mjpeg',cv2.VideoWriter_fourcc('M','J','P','G'), (frame_per_sec), (frame_width,frame_height))
while(True):
ret, frame = cap.read()
if ret == True:
# Write the frame into the file 'output.mjpeg'
out.write(frame)
# Display the resulting frame
cv2.imshow('frame',frame)
# Press Q on keyboard to stop recording
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
While it will run, I am getting the following error(s),
[ WARN:0] OpenCV | GStreamer warning: Cannot query video position: status=0, value=-1, duration=-1
OpenCV: FFMPEG: tag 0x67706a6d/'mjpg' is not supported with codec id 7 and format 'mjpeg / raw MJPEG video'
What can I do to resolve these? I've tried changing the case, ('M','J','P','G' to 'm','j','p','g') with no success.
Appreciate any suggestions regarding resolving the above issue, as well as the GStreamer issue. Thanks in advance.
.mjpeg is not a valid suffix for any known container format.
I'm sure you didn't intend to write a raw MJPG stream without a container. That is very very rarely useful at all and requires expert knowledge.
You have two options:
use MJPG in a .avi container, because that's built into OpenCV and doesn't even require ffmpeg
use whatever ffmpeg understands, which would be a .mpg container, or .mov or .mkv or whatever else

How can I read m3u8 format video stream and save it with opencv in python?

I'm trying to save video stream, and to timelapse it. I know how to read any video from computer (for example mp4 format) and make a timelapse (I tried, I succeeded). Now I'm trying to do the same with a video stream.
I have link for m3u8 video https://wstream.comanet.cz:1943/live/Vrchlabi-sjezdovka2.stream_360p/playlist.m3u8, I'm reading video like this:
(Initialization:)
import cv2 as cv
url = 'https://wstream.comanet.cz:1943/live/Vrchlabi-sjezdovka2.stream_360p/playlist.m3u8'
fourcc = cv.VideoWriter_fourcc(*'mp4v')
height = video.get(cv.CAP_PROP_FRAME_HEIGHT)
width = video.get(cv.CAP_PROP_FRAME_WIDTH)
outp = cv.VideoWriter(save_path, fourcc, 60,(int(width), int(height)))
video = cv.VideoCapture("url")
dir_stream = "streamframes"
if not os.path.exists(dir_stream):
os.makedirs(dir_stream)
if not video.isOpened():
print("Error opening video file.")
(There is a main part - loop:)
name = 0
while video.isOpened():
ret, frame = video.read()
name += 1
filename = f"{dir_stream}/{name}.jpg"
cv.imwrite(filename, frame)
f = cv.imread(filename)
outp.write(f)
I don't like the way of saving the video... anyway - it's not completely wrong... it kind of works, but after few read frames (sometimes it's 153, 212 etc), ret value is returning False value and code gets into infinite loop. After I stopped the program, my video was saved and I could play it, it was just short (cause it was not recording as long as I wanted, because of infinite loop)...
In the "while" part I also tried...:
while video.isOpened():
ret, frame = video.read()
if ret:
frame_r = cv.imread(frame)
outp.write(frame_r)
... it's much more nice, but cv.imread(frame) was not working so I did it in dirty way u can see above.
My goal is recording online stream with python for some time (e.g. for 5 hours), I don't need record with 30fps, (e.g. 1fps is also fine).
Can anyone help me with this problem? Or do you have some advice? Why ret value returns False after some random time? Do you have other solution? I'll be really thankful for your help, it's for my school project.

Saving a video capture in python with openCV : empty video

I'm new in Python (2.7) and I try to work on video processing (with module openCv "cv2"). Starting with tutorials, I try to use the script of this tutorial : paragraph "Saving a video".
Everything works fine excepting that the video I'm saving is empty. I can find output.avi in my directory but its memory size is 0kb an, of course when I run it, no video is displayed.
After a few changes here is my code :
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
#fourcc = cv2.VideoWriter_fourcc(*'DIVX')
fourcc = cv2.cv.CV_FOURCC(*'DIVX')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
# write the flipped frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
Does anyone know why it is not working properly ?
Thanks a lot.
Edwin
I never worked with openCV, but I bet the problem is in
cap = cv2.VideoCapture(0)
This is a C version of the VideoCapture method http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture
Maybe you can try to do the same. Something like
cap = cv2.VideoCapture(0)
if (not cap.isOpened()):
print "Error"
EDIT: just downloaded Python and OpenCV and discovered the problem was the codec. Try to change
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
for
out = cv2.VideoWriter('output.avi', -1, 20.0, (640,480))
and select the codec by hand.
Could be the output resolution is different from the input. Check width and height of cap.
size = (int(cap.get(3)), int(cap.get(4)))
Change either your camera or the output resolution.
I have Windows 10, Python3.7.6, OpenCV 4.2.0. In my case, the problem is video encoder. Both "XVID" and "X264" result in an empty output video. I changed the encoder to "DIVX" and the video is generated successfully.

Making a video with opencv and ffmpeg. How to find the right color format?

I have a webcam video recorder program built with python, opencv and ffmpeg
It works ok except that the color of the video is more blue than the reality. The problem seems to come from color format of images.
It seems that OpenCv is giving BGR images and ffmpeg+libx264 is expecting YUV420p. I've read that YUV420p correspond to YCbCr.
opencv has no conversion from BGR to YCbCr. It only has a conversion to YCrCb.
I have made some searchs and tried different alternatives to try converting opencv image to something that could be ok for ffmpeg+libx264. None is working. At this point, I am a bit lost and I would appreciate any pointer that could help me to fix this color issue.
You are right, the default pixel format of OpenCV is BGR.
The equivalent format on the ffmpeg side would be BGR24, so you don't need to convert it to YUV420p if you don't want to.
This post shows how to use a python application to capture frames from the webcam and write the frames to stdout. The purpose is to invoke this app on the cmd-line and pipe the result directly to the ffmpeg application, which stores the frames on the disk. Quite clever indeed!
capture.py:
import cv, sys
cap = cv.CaptureFromCAM(0)
if not cap:
sys.stdout.write("failed CaptureFromCAM")
while True :
if not cv.GrabFrame(cap) :
break
frame = cv.RetrieveFrame(cap)
sys.stdout.write( frame.tostring() )
And the command to be executed on the shell is:
python capture.py | ffmpeg -f rawvideo -pix_fmt bgr24 -s 640x480 -r 30 -i - -an -f avi -r 30 foo.avi
Where:
-r gives the frame rate coming off the camera
-an says "don't encode audio"
I tested this solution on my Mac OS X with OpenCV 2.4.2.
EDIT:
In case you haven't tried to record from the camera and use OpenCV to write the video to an mp4 file on the disk, here we go:
import cv, sys
cap = cv.CaptureFromCAM(0) # 0 is for /dev/video0
if not cap:
sys.stdout.write("!!! Failed CaptureFromCAM")
sys.exit(1)
frame = cv.RetrieveFrame(cap)
if not frame:
sys.stdout.write("!!! Failed to retrieve first frame")
sys.exit(1)
# Unfortunately, the following instruction returns 0
#fps = cv.GetCaptureProperty(cap, cv.CV_CAP_PROP_FPS)
fps = 25.0 # so we need to hardcode the FPS
print "Recording at: ", fps, " fps"
frame_size = cv.GetSize(frame)
print "Video size: ", frame_size
writer = cv.CreateVideoWriter("out.mp4", cv.CV_FOURCC('F', 'M', 'P', '4'), fps, frame_size, True)
if not writer:
sys.stdout.write("!!! Error in creating video writer")
sys.exit(1)
while True :
if not cv.GrabFrame(cap) :
break
frame = cv.RetrieveFrame(cap)
cv.WriteFrame(writer, frame)
cv.ReleaseVideoWriter(writer)
cv.ReleaseCapture(cap)
I've tested this with Python 2.7 on Mac OS X and OpenCV 2.4.2.
Have you tried switching the Cb/Cr channels in OpenCV using split and merge ?
Checked the conversion formulas present in: http://en.wikipedia.org/wiki/YCbCr?
The libx264 codec is able to process BGR images. No need to use any conversion to YCbCr. NO need to give a spcific pix_ftm to ffmpeg. I was using RGB and it was causing the blueish effect on the video.
The solution was simply to use the original image retuned by the camera without any conversion. :)
I tried this in my previous investigation and it was crashing the app. The solution is to copy the frame returned by the camera.
frame = opencv.QueryFrame(camera)
if not frame:
return None, None
# RGB : use this one for displaying on the screen
im_rgb = opencv.CreateImage(self.size, opencv.IPL_DEPTH_8U, 3)
opencv.CvtColor(frame, im_rgb, opencv.CV_BGR2RGB)
# BGR : Use this one for the video
im_bgr = opencv.CreateImage(self.size, opencv.IPL_DEPTH_8U, 3)
opencv.Copy(frame, im_bgr)
return im_rgb, im_bgr
I've already answered this here. But my VidGear Python Library automates the whole process of pipelining OpenCV frames into FFmpeg and also robustly handles the format conversion. Here's a basic python example:
# import libraries
from vidgear.gears import WriteGear
import cv2
output_params = {"-vcodec":"libx264", "-crf": 0, "-preset": "fast"} #define (Codec,CRF,preset) FFmpeg tweak parameters for writer
stream = cv2.VideoCapture(0) #Open live webcam video stream on first index(i.e. 0) device
writer = WriteGear(output_filename = 'Output.mp4', compression_mode = True, logging = True, **output_params) #Define writer with output filename 'Output.mp4'
# infinite loop
while True:
(grabbed, frame) = stream.read()
# read frames
# check if frame empty
if not is grabbed:
#if True break the infinite loop
break
# {do something with frame here}
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# write a modified frame to writer
writer.write(gray)
# Show output window
cv2.imshow("Output Frame", frame)
key = cv2.waitKey(1) & 0xFF
# check for 'q' key-press
if key == ord("q"):
#if 'q' key-pressed break out
break
cv2.destroyAllWindows()
# close output window
stream.release()
# safely close video stream
writer.close()
# safely close writer
Source: https://github.com/abhiTronix/vidgear/wiki/Compression-Mode:-FFmpeg#2-writegear-classcompression-mode-with-opencv-directly
You can check out full VidGear Docs for more advanced applications and exciting features.
Hope that helps!

OpenCV: Writing a video from a cam, strange results (Python and Mac)

I am trying to grab frames from a webcam and then writing them in a video. It works and the video shows something but it is useless.
Here you can see an example of the videos I get:
THe script is quite big so I will try to pick the relevant pieces for this problem:
import cv
capture = cv.CaptureFromCAM(1) # from webcam
frame = cv.QueryFrame(capture)
newvideo = 'Videos/%d_%d_%d_%d_%d_%d.avi' % (localtime()[0],localtime()[1],localtime()[2],localtime()[3],localtime()[4],localtime()[5])
video = cv.CreateVideoWriter(newvideo, cv.CV_FOURCC('D','I','V','X'), 30, cv.GetSize(frame), 1)
while(1):
frame = cv.QueryFrame(capture)
cv.WriteFrame(video, frame)
key = cv.WaitKey( int((1/30.)*1000)+1 )
Tip: start coding defensively and check the return of the calls you make. For instance:
video = cv.CreateVideoWriter(newvideo, cv.CV_FOURCC('D','I','V','X'), 30, cv.GetSize(frame), 1)
if not video :
print "Error in creating video writer"
sys.exit(1)
This might be a codec related problem, so try to create your video with other codecs:
video = cv.CreateVideoWriter(newvideo, cv.CV_FOURCC('F','L','V','1'), 30, cv.GetSize(frame), 1)
It might be a good idea to update the ones you've installed.

Categories