我想用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
的最后一个论点也是错误的,但我不确定它应该是什么。
答案 0 :(得分:8)
您尝试适应的示例是针对OpenCV 2.0的新python接口。这可能是前缀和非前缀函数名称(cv.cvSetData()
与cv.SetData()
)之间混淆的原因。
OpenCV 2.0现在附带两组python绑定:
opencv.{cv,highgui,ml}
模块cv.pyd
),它包含所有OpenCV功能(包括highgui
和ml
模块。)错误消息背后的原因是SWIG包装器不处理从python字符串到普通C缓冲区的转换。但是,SWIG包装器附带opencv.adaptors
模块,该模块旨在支持从numpy
和PIL
图像到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-based wrapper。它带有实用功能,用于在例如美国国家公python字符串和C缓冲区。快速查看google code search似乎表明这是一种有效的方法。
关于cvSetData()
函数的第三个参数,图像缓冲区的大小,但图像步骤。该步骤是图像一行中的字节数,即pixel_depth * number_of_channels * image_width
。 pixel_depth
参数是与一个通道关联的数据的字节大小。在您的示例中,它只是图像宽度(只有一个通道,每个像素一个字节)。
答案 1 :(得分:4)
让swig和new 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中的详细信息。
答案 2 :(得分: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的图像的任何其他用途也是必要的。
答案 3 :(得分:0)
我不是专家,但我设法使用此代码从PIL图像中获取opencv图像:
import opencv
img = opencv.adaptors.PIL2Ipl(pilimg)