2012-09-19 57 views
10

Tengo un programa de videograbadora de cámara web creado con python, opencv y ffmpegHacer un video con opencv y ffmpeg. ¿Cómo encontrar el formato de color correcto?

Funciona bien, excepto que el color del video es más azul que la realidad. El problema parece provenir del formato de color de las imágenes.

Parece que OpenCv está dando imágenes BGR y ffmpeg + libx264 está esperando YUV420p. He leído que YUV420p corresponde a YCbCr.

opencv no tiene conversión de BGR a YCbCr. Solo tiene una conversión a YCrCb.

He realizado algunas búsquedas y he probado diferentes alternativas para tratar de convertir la imagen de opencv a algo que podría estar bien para ffmpeg + libx264. Ninguno está funcionando. En este punto, estoy un poco perdido y agradecería cualquier apuntador que pueda ayudarme a solucionar este problema de color.

Respuesta

13

Tiene razón, el formato de píxeles predeterminado de OpenCV es BGR.

El formato equivalente en el lado ffmpeg sería BGR24, por lo que no necesita convertirlo a YUV420p si no lo desea.

This post muestra cómo utilizar una aplicación de Python para capturar fotogramas de la cámara web y escribir los marcos en stdout. El objetivo es invocar esta aplicación en la línea de cmd y canalizar el resultado directamente a la aplicación ffmpeg, que almacena los marcos en el disco. ¡Muy inteligente!

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()) 

Y el comando a ejecutar en la cáscara es:

python capture.py | ffmpeg -f rawvideo -pix_fmt bgr24 -s 640x480 -r 30 -i - -an -f avi -r 30 foo.avi 

Dónde:

  • -r da el marco tasa que sale de la cámara
  • -un dice "no codificar audio"

He probado esta solución en mi Mac OS X con OpenCV 2.4.2.

EDIT:

En caso de que no haya tratado de registro de la cámara y utilizar OpenCV para escribir el vídeo a un archivo MP4 en el disco, aquí vamos:

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) 

He probado esto con Python 2.7 en Mac OS X y OpenCV 2.4.2.

+0

Gracias por su respuesta. No tuve tiempo de verificar la solución, pero parece interesante. Intenté usar el bgr24 pix_fmt pero no funciona con el códec libx264. No estoy seguro de si realmente necesito usar libx264. Necesito una solución multiplataforma (Windows, Mac, Linux) y, como consecuencia, es posible que se necesite libx264. Necesito verificar – luc

+0

En Windows libx264 es el códec predeterminado y causa que la imagen tenga colores incorrectos porque no es compatible con bgr24 pix_fmt – luc

+0

Lamento preguntar, pero ¿por qué no usa OpenCV para crear el archivo de video? – karlphillip

0

¿Comprobó las fórmulas de conversión presentes en: http://en.wikipedia.org/wiki/YCbCr?

+0

Gracias por el enlace, pero estoy un poco perdido entre todas estas fórmulas. ¿Qué recomendarías para implementarlo? – luc

1

¿Ha intentado cambiar los canales Cb/Cr en OpenCV usando split y merge?

+0

Intenté diferentes conversiones. ¿Cuál recomendarías? – luc

+0

Te sugiero que simplemente cambies los canales Cb y Cr. En YCbCr, Y representa la parte de "Luminancia", que es más o menos el nivel de gris. Las informaciones de color se almacenan en 2 canales "Chrominance", Cr (como en Chrominance Red) y Cb (chrominance blue). Como dijiste, OpenCV convierte a YCrCb y ffmpeg YUV = YCbCr. Este + el hecho de que tus imágenes se vean azuladas me hace pensar que simplemente puedes intercambiar los canales de crominancia, Cr <-> Cb. – remi

+0

Gracias. Ayudó a encontrar la solución. Creé un convertidor usando Split and Merge y me di cuenta de que tenía una doble conversión y que usar Copy era suficiente :) – luc

0

El códec libx264 puede procesar imágenes BGR. No es necesario usar ninguna conversión a YCbCr. NO es necesario dar un pix_ftm específico a ffmpeg. Estaba usando RGB y estaba causando el efecto azulado en el video.

La solución fue simplemente utilizar la imagen original reajustada por la cámara sin ninguna conversión. :)

Intenté esto en mi investigación anterior y estaba bloqueando la aplicación. La solución es copiar el cuadro devuelto por la cámara.

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 
Cuestiones relacionadas