Как мне создать изображение OpenCV из изображения PIL? - PullRequest
10 голосов
/ 30 октября 2009

Я хочу выполнить некоторую обработку изображения с OpenCV (в Python), но мне нужно начать с объекта PIL Image, поэтому я не могу использовать вызов cvLoadImage(), так как для этого требуется имя файла.

Этот рецепт (адаптированный с http://opencv.willowgarage.com/wiki/PythonInterface) не работает, потому что cvSetData жалуется argument 2 of type 'void *'. Есть идеи?

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

Я думаю, что последний аргумент cvSetData тоже неверен, но я не уверен, каким он должен быть.

Ответы [ 4 ]

8 голосов
/ 30 октября 2009

Пример, который вы пытались адаптировать, относится к новому интерфейсу Python для OpenCV 2.0. Вероятно, это является причиной путаницы между именами префиксных и нефиксированных функций (cv.cvSetData() против cv.SetData()).

OpenCV 2.0 теперь поставляется с двумя наборами привязок Python:

  • Оболочка Python "старого стиля" , пакет python с модулями opencv.{cv,highgui,ml}
  • Новый интерфейс , расширение Python C (cv.pyd), охватывающее все функциональные возможности OpenCV (включая модули highgui и ml.)

Причиной сообщения об ошибке является то, что оболочка SWIG не обрабатывает преобразование строки Python в обычный старый C-буфер. Однако оболочка SWIG поставляется с модулем opencv.adaptors, который предназначен для поддержки преобразования изображений numpy и PIL в OpenCV.

Следующий (проверенный) код должен решить исходную проблему (преобразование из PIL в OpenCV) с использованием интерфейса 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)

Однако это не решает тот факт, что функция cv.cvSetData() всегда будет сбоить (с текущей реализацией оболочки SWIG). Затем вы можете использовать оболочку нового стиля, которая позволяет использовать функцию cv.SetData() так, как вы ожидаете:

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

Третий подход - переключить ваш Python-интерфейс OpenCV на оболочку на основе ctypes . Он поставляется с функциями полезности для явного преобразования данных, например, между строки Python и C-буферы. Быстрый просмотр Google Code Search , кажется, показывает, что это рабочий метод.

Относительно третьего параметра функции cvSetData(), размер буфера изображения, но шаг изображения. Шаг - это количество байтов в одной строке вашего изображения, которое составляет pixel_depth * number_of_channels * image_width. Параметр pixel_depth - это размер в байтах данных, связанных с одним каналом. В вашем примере это будет просто ширина изображения (только один канал, один байт на пиксель).

4 голосов
/ 27 марта 2010

Это действительно сбивает с толку иметь и Swig и новую привязку Python. Например, в OpenCV 2.0 cmake может принимать как BUILD_SWIG_PYTHON_SUPPORT, так и BUILD_NEW_PYTHON_SUPPORT. Но, во всяком случае, я как бы выяснил большинство подводных камней.

В случае использования «import cv» (новая привязка python) требуется еще один шаг.

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

Преобразование необходимо для изображений RGB, поскольку в PIL и IplImage последовательность отличается. То же самое относится к Ipl для PIL.

Но если вы используете opencv.adaptors, об этом уже позаботятся. Если вам интересно, вы можете посмотреть подробности в adaptors.py.

3 голосов
/ 07 сентября 2010

Я сделал это, используя привязки python2.6 OpenCV2.1:

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

Поворот изображения и обращение строки - это замена RGB на BGR, который используется в кодировании видео OpenCV. Я предполагаю, что это также будет необходимо для любого другого использования изображения, преобразованного из PIL в OpenCV.

0 голосов
/ 20 августа 2012

Я не эксперт, но мне удалось получить изображение opencv из изображения PIL с этим кодом:

import opencv

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