使用 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 制作视频。如何找到正确的颜色格式?的主要内容,如果未能解决你的问题,请参考以下文章

如何用ffmpeg制作马赛克,而不会同时播放每个视频?

ffmpeg 和 SDL 的区别和联系? 谢谢

将 pi 的 opencv 视频传输到 ffmpeg 以进行 Youtube 流式传输

基于ffmpeg+SDL视频播放器制作任务概述

ffmpeg的安装--opencv视频处理必备

FFmpeg 从放置在不同文件夹中的图像制作视频