¿Cómo creo una imagen OpenCV a partir de una imagen PIL?

Quiero hacer algo de procesamiento de imágenes con OpenCV (en Python), pero tengo que comenzar con un objeto PIL Image , así que no puedo usar la llamada cvLoadImage() , ya que toma un nombre de archivo.

Esta receta (adaptada de http://opencv.willowgarage.com/wiki/PythonInterface ) no funciona porque cvSetData queja del argument 2 of type 'void *' . ¿Algunas ideas?

 from opencv.cv import * from PIL import Image pi = Image.open('foo.png') # PIL image ci = cvCreateImage(pi.size, IPL_DEPTH_8U, 1) # OpenCV image data = pi.tostring() cvSetData(ci, data, len(data)) 

Creo que el último argumento de cvSetData es incorrecto, pero no estoy seguro de lo que debería ser.

El ejemplo que intentaste adaptar es para la nueva interfaz de Python para OpenCV 2.0. Este es probablemente el origen de la confusión entre los nombres de función prefijados y no prefijados ( cv.cvSetData() versus cv.SetData() ).

OpenCV 2.0 ahora se envía con dos conjuntos de enlaces de python:

  • El “python wrapper” de estilo antiguo , un paquete de python con los opencv.{cv,highgui,ml}
  • La nueva interfaz , una extensión de Python C ( cv.pyd ), que envuelve todas las funcionalidades de OpenCV (incluidos los módulos highgui y ml ).

La razón detrás del mensaje de error es que el envoltorio SWIG no maneja la conversión de una cadena de python a un búfer de C simple. Sin embargo, el envoltorio SWIG viene con el módulo opencv.adaptors , que está diseñado para admitir conversiones de imágenes numpy y PIL a OpenCV.

El siguiente código (probado) debería resolver su problema original (conversión de PIL a OpenCV), usando la interfaz SWIG:

 # PIL to OpenCV using the SWIG wrapper from opencv import cv, adaptors, highgui import PIL pil_img = PIL.Image.open(filename) cv_img = adaptors.PIL2Ipl(pil_img) highgui.cvNamedWindow("pil2ipl") highgui.cvShowImage("pil2ipl", cv_img) 

Sin embargo, esto no resuelve el hecho de que la función cv.cvSetData() siempre fallará (con la implementación actual del envoltorio SWIG). Luego puede usar el envoltorio de nuevo estilo, que le permite usar la función cv.SetData() como cabría esperar:

 # PIL to OpenCV using the new wrapper import cv import PIL pil_img = PIL.Image.open(filename) cv_img = cv.CreateImageHeader(pil_img.size, cv.IPL_DEPTH_8U, 3) # RGB image cv.SetData(cv_img, pil_img.tostring(), pil_img.size[0]*3) cv.NamedWindow("pil2ipl") cv.ShowImage("pil2ipl", cv_img) 

Un tercer enfoque sería cambiar la interfaz de Python de OpenCV al envoltorio basado en ctypes . Viene con funciones de utilidad para la conversión explícita de datos entre, por ejemplo, cadenas de python y buffers en C. Una mirada rápida en la búsqueda de códigos de Google parece indicar que este es un método de trabajo.

Con respecto al tercer parámetro de la función cvSetData() , el tamaño del búfer de imagen, pero el paso de la imagen. El paso es el número de bytes en una fila de tu imagen, que es pixel_depth * number_of_channels * image_width . El parámetro pixel_depth es el tamaño en bytes de los datos asociados a un canal. En su ejemplo, sería simplemente el ancho de la imagen (solo un canal, un byte por píxel).

Es realmente confuso tener un gulp y un nuevo enlace de python. Por ejemplo, en OpenCV 2.0, cmake puede aceptar tanto BUILD_SWIG_PYTHON_SUPPORT como BUILD_NEW_PYTHON_SUPPORT. Pero de todos modos, me di cuenta de la mayoría de las trampas.

En el caso de usar “import cv” (el nuevo enlace de python), se necesita un paso más.

 cv.SetData(cv_img, pil_img.tostring(), pil_img.size[0]*3) cv.CvtColor(cv_img, cv_img, cv.CV_RGB2BGR) 

La conversión es necesaria para las imágenes RGB porque la secuencia es diferente en PIL e IplImage. Lo mismo se aplica a Ipl a PIL.

Pero si usas opencv.adaptors, ya está cuidado. Puede ver los detalles en adaptors.py si está interesado.

Hice esto usando los enlaces python2.6 de OpenCV2.1:

  ... cv_img = cv.CreateImageHeader(img.size, cv.IPL_DEPTH_8U, 3) cv.SetData(cv_img, img.rotate(180).tostring()[::-1]) ... 

La rotación de la imagen y la reversión de la cadena es para cambiar RGB a BGR, que se utiliza en la encoding de video OpenCV. Supongo que esto también sería necesario para cualquier otro uso de una imagen convertida de PIL a OpenCV.

No soy un experto, pero me las arreglé para obtener una imagen abierta de una imagen PIL con este código:

 import opencv img = opencv.adaptors.PIL2Ipl(pilimg)