您尝试调整的示例适用于 OpenCV 2.0 的新 python 接口。这可能是前缀和非前缀函数名称(cv.cvSetData()
vs cv.SetData()
)之间混淆的根源。
OpenCV 2.0 现在附带两组 python 绑定:
- “老式”python 包装器,一个带有
opencv.{cv,highgui,ml}
模块的 python 包
- 新接口,一个 python C 扩展(
cv.pyd
),它包装了所有 OpenCV 功能(包括highgui
和ml
模块)。
错误消息背后的原因是 SWIG 包装器不处理从 python 字符串到普通 C 缓冲区的转换。但是,SWIG 包装器随opencv.adaptors
模块一起提供,旨在支持从OpenCVnumpy
和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 的 wrapper。它带有实用函数,用于在 python 字符串和 C 缓冲区之间进行显式数据转换。快速浏览谷歌代码搜索似乎表明这是一种工作方法。
关于cvSetData()
函数的第三个参数,图像缓冲区的大小,但图像步长。step 是图像的一行中的字节数,即pixel_depth * number_of_channels * image_width
. 该pixel_depth
参数是与一个通道关联的数据的字节大小。在您的示例中,它只是图像宽度(只有一个通道,每个像素一个字节)。