12

我想用 OpenCV(在 Python 中)做一些图像处理,但我必须从一个 PILImage对象开始,所以我不能使用这个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

4 回答 4

9

您尝试调整的示例适用于 OpenCV 2.0 的新 python 接口。这可能是前缀和非前缀函数名称(cv.cvSetData()vs cv.SetData())之间混淆的根源。

OpenCV 2.0 现在附带两组 python 绑定:

  • 老式”python 包装器,一个带有opencv.{cv,highgui,ml}模块的 python 包
  • 接口,一个 python C 扩展(cv.pyd),它包装了所有 OpenCV 功能(包括highguiml模块)。

错误消息背后的原因是 SWIG 包装器不处理从 python 字符串到普通 C 缓冲区的转换。但是,SWIG 包装器随opencv.adaptors模块一起提供,旨在支持从OpenCVnumpyPIL图像到 OpenCV 的转换。

以下(经过测试的)代码应该使用 SWIG 接口解决您的原始问题(从 PIL 转换为 OpenCV):

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

第三种方法是将您的 OpenCV python 接口切换到基于 ctypes 的 wrapper。它带有实用函数,用于在 python 字符串和 C 缓冲区之间进行显式数据转换。快速浏览谷歌代码搜索似乎表明这是一种工作方法。

关于cvSetData()函数的第三个参数,图像缓冲区的大小,但图像步长。step 是图像的一行中的字节数,即pixel_depth * number_of_channels * image_width. 该pixel_depth参数是与一个通道关联的数据的字节大小。在您的示例中,它只是图像宽度(只有一个通道,每个像素一个字节)。

于 2009-10-30T20:06:55.823 回答
4

It's really confusing to have both swig and new python binding. For example, in the OpenCV 2.0, cmake can accept both BUILD_SWIG_PYTHON_SUPPORT and BUILD_NEW_PYTHON_SUPPORT. But anyway, I kinda figured out most pitfalls.

In the case of using "import cv" (the new python binding), one more step is needed.

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

The conversion is necessary for RGB images because the sequence is different in PIL and IplImage. The same applies to Ipl to PIL.

But if you use opencv.adaptors, it's already taken care of. You can look into the details in adaptors.py if interested.

于 2010-03-27T05:14:48.720 回答
3

我使用 OpenCV2.1 的 python2.6 绑定做到了这一点:

    ...
    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 的图像的任何其他用途也是必要的。

于 2010-09-07T09:31:52.970 回答
0

我不是专家,但我设法使用以下代码从 PIL 图像中获取了 opencv 图像:

import opencv

img = opencv.adaptors.PIL2Ipl(pilimg)
于 2012-08-20T03:53:00.403 回答