Создание видео с opencv и ffmpeg. Как найти правильный цветной формат?

У меня есть программа видеомагнитофона веб-камеры, созданная с помощью python, opencv и ffmpeg

Он работает нормально, за исключением того, что цвет видео более синий, чем реальность. Проблема, похоже, исходит из цветового формата изображений.

Кажется, что OpenCv дает изображения BGR, а ffmpeg + libx264 ожидает YUV420p. Я читал, что YUV420p соответствует YCbCr.

opencv не имеет преобразования из BGR в YCbCr. Он имеет только преобразование в YCrCb.

Я сделал несколько поисков и попробовал разные альтернативы, чтобы попробовать конвертировать opencv-образ в то, что может быть хорошо для ffmpeg + libx264. Никто не работает. На данный момент я немного потерян, и я был бы признателен за любой указатель, который мог бы помочь мне исправить эту проблему цвета.

Ответ 1

Вы правы, формат пикселей по умолчанию для OpenCV BGR.

Эквивалентный формат на стороне ffmpeg будет BGR24, поэтому вам не нужно преобразовывать его в YUV420p, если вы этого не хотите.

Этот пост показывает, как использовать приложение python для захвата фреймов с веб-камеры и записи фреймов в stdout. Цель состоит в том, чтобы вызвать это приложение в cmd-строке и передать результат непосредственно в приложение 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() )

И команда, которая должна быть выполнена в оболочке:

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.

EDIT:

Если вы не пытались выполнить запись с камеры и использовать 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)

Я тестировал это с помощью Python 2.7 на Mac OS X и OpenCV 2.4.2.

Ответ 2

Вы пытались переключить каналы Cb/Cr в OpenCV, используя split и merge?

Ответ 4

Кодек libx264 способен обрабатывать изображения BGR. Не нужно использовать какое-либо преобразование в YCbCr. НЕТ, чтобы передать spfific pix_ftm в ffmpeg. Я использовал 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

Я уже ответил на это здесь. Но моя библиотека 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 для более продвинутых приложений и захватывающих функций.

Надеюсь, это поможет!