使用 opencv 和 ffmpeg 制作视频。如何找到正确的颜色格式?
Posted
技术标签:
【中文标题】使用 opencv 和 ffmpeg 制作视频。如何找到正确的颜色格式?【英文标题】:Making a video with opencv and ffmpeg. How to find the right color format? 【发布时间】:2012-09-12 06:33:05 【问题描述】:我有一个使用 python、opencv 和 ffmpeg 构建的网络摄像头录像机程序
除了视频的颜色比实际颜色更蓝之外,一切正常。问题似乎来自图像的颜色格式。
似乎 OpenCv 正在提供 BGR 图像,而 ffmpeg+libx264 正在期待 YUV420p。我读过 YUV420p 对应 YCbCr。
opencv 没有从 BGR 到 YCbCr 的转换。它只有转换为 YCrCb。
我进行了一些搜索并尝试了不同的替代方法来尝试将 opencv 图像转换为适合 ffmpeg+libx264 的图像。没有工作。在这一点上,我有点迷茫,如果有任何可以帮助我解决此颜色问题的指针,我将不胜感激。
【问题讨论】:
【参考方案1】:你是对的,OpenCV的默认像素格式是BGR。
ffmpeg 端的等效格式是BGR24,所以如果你不想转换成YUV420p 就不用了。
This post 展示了如何使用 python 应用程序从网络摄像头捕获帧并将帧写入 stdout。目的是在 cmd-line 上调用此应用程序并将结果直接通过管道传输到 ffmpeg 应用程序,该应用程序将帧存储在磁盘上。确实很聪明!
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() )
而要在shell上执行的命令是:
python capture.py | ffmpeg -f rawvideo -pix_fmt bgr24 -s 640x480 -r 30 -i - -an -f avi -r 30 foo.avi
在哪里:
-r 给出来自相机的帧速率 -an 说“不要编码音频”
我在我的 Mac OS X 上使用 OpenCV 2.4.2 测试了这个解决方案。
编辑:
如果您还没有尝试从相机录制并使用 OpenCV 将视频写入磁盘上的 mp4 文件,我们开始吧:
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)
我已经在 Mac OS X 和 OpenCV 2.4.2 上使用 Python 2.7 对此进行了测试。
【讨论】:
感谢您的回答。我还没有时间检查解决方案,但它看起来很有趣。我已经尝试使用 bgr24 pix_fmt 但它不适用于 libx264 编解码器。我不确定我是否真的需要使用 libx264。我需要一个跨平台的解决方案(windows、mac、linux),因此可能需要 libx264。我需要检查一下。 在 Windows 上 libx264 是默认编解码器,由于它与 bgr24 pix_fmt 不兼容而导致图像颜色错误 不好意思问一下,为什么不用OpenCV来创建视频文件呢? 我认为 pb 是相对于 windows 平台的。无论如何,谢谢你的回答,这很有趣。它并没有解决我的问题,但它(以及您在 opencv 上回答的所有令人印象深刻的问题)帮助我更好地理解了 opencv 的工作原理并解决了我的问题。它值得赏金:) 我再次阅读了您的答案,实际上它从一开始就是正确的答案。只是我的实现不正确。它也值得被接受:)【参考方案2】:您是否尝试过在 OpenCV 中使用 split 和 merge 切换 Cb/Cr 通道?
【讨论】:
我尝试了不同的转换。你会推荐哪一个? 我建议你只是交换 Cb 和 Cr 频道。在 YCbCr 中,Y 代表“亮度”部分,即或多或少的灰度级。颜色信息存储在 2 个“色度”通道中,Cr(如色度红)和 Cb(色度蓝)。正如你所说,OpenCV 转换为 YCrCb,而 ffmpeg YUV = YCbCr。这+你的图像看起来偏蓝的事实让我认为你可以简单地交换色度通道,CrCb。 谢谢。它有助于找到解决方案。我已经使用 Split and Merge 制作了一个转换器,我意识到我有一个双重转换并且使用 Copy 就足够了:)【参考方案3】:检查了存在于:http://en.wikipedia.org/wiki/YCbCr?中的转换公式?
【讨论】:
感谢您的链接,但我有点迷失在所有这些公式之间。为了实施它,您有什么建议?【参考方案4】:libx264 编解码器能够处理 BGR 图像。无需使用任何转换为 YCbCr。不需要给 ffmpeg 一个特定的 pix_ftm。我使用的是 RGB,导致视频呈现蓝色效果。
解决方案是简单地使用相机重新调整的原始图像,无需任何转换。 :)
我在之前的调查中尝试过这个,但它导致应用程序崩溃。解决方案是复制相机返回的帧。
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
【讨论】:
【参考方案5】:我已经回答了这个here。但是我的VidGear
Python 库自动化了将 OpenCV 帧流水线化到 FFmpeg 的整个过程,并且还稳健地处理了格式转换。这是一个基本的python示例:
# 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
来源:https://github.com/abhiTronix/vidgear/wiki/Compression-Mode:-FFmpeg#2-writegear-classcompression-mode-with-opencv-directly
您可以查看完整的VidGear Docs,了解更高级的应用程序和令人兴奋的功能。
希望有帮助!
【讨论】:
以上是关于使用 opencv 和 ffmpeg 制作视频。如何找到正确的颜色格式?的主要内容,如果未能解决你的问题,请参考以下文章