如何从 PIL 图像创建 OpenCV 图像?
Posted
技术标签:
【中文标题】如何从 PIL 图像创建 OpenCV 图像?【英文标题】:How do I create an OpenCV image from a PIL image? 【发布时间】:2010-12-11 15:45:05 【问题描述】:我想用 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
的最后一个参数也是错误的,但我不确定应该是什么。
【问题讨论】:
您在上面输入的代码中包含未定义的名称(cvSetData),因此很难知道您是否真的尝试过。 @Jonathan:我没有收到您提到的错误。 cvSetData 确实是 opencv.cv 中定义的有效函数 目前回答的状态如何? 【参考方案1】:您尝试调整的示例是针对 OpenCV 2.0 的新 python 接口。这可能是前缀和非前缀函数名之间混淆的根源(cv.cvSetData()
与 cv.SetData()
)。
OpenCV 2.0 现在附带两组 python 绑定:
"old-style" python wrapper,一个带有opencv.cv,highgui,ml
模块的python 包
new interface,一个 python C 扩展 (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()
函数的第三个参数,图像缓冲区的大小,而是图像步长。 step 是图像的一行中的字节数,即pixel_depth * number_of_channels * image_width
。 pixel_depth
参数是与一个通道关联的数据的大小(以字节为单位)。在您的示例中,它只是图像宽度(只有一个通道,每个像素一个字节)。
【讨论】:
@sevas:我还没有接受你的回答(目前),因为我am使用的是 OpenCV 2.0 版。在我将 cv.CreateImageHeader 更改为 cvCreateImage 并将 cv.SetData 更改为 cvSetData 之前,我链接到的页面上的配方根本不起作用,所以我仍然对此感到困惑。我将使用 ctypes-opencv 尝试您的方法,如果可行,我将在此处发布我的发现。 @scrible:我添加了有关 OpenCV 2.0 附带的两组并发绑定的信息。不过,我可能会继续寻找更好的解决方案。 @scrible :我使用我能找到的最新信息(特别是适配器模块和两组 python 绑定)更新了答案。 对于第三个参数,是否必须是 4 的倍数?在这个网站:opencv.willowgarage.com/wiki/PythonInterface,有这样的文字:“我们认为 SetData 必须有一个步长是 4 的倍数” 我正在尝试使用您在此处显示的第一种方法,除了我将数字 1 作为 CreateImageHeader() 函数的第三个参数,并且 OpenCV 窗口中显示的图像全部被打乱.我也尝试将参数 3 留在那里。还是一样。我加载的图片是PNG。请问有什么问题吗?【参考方案2】:同时拥有 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,它已经被处理好了。如果有兴趣,可以查看 adapters.py 中的详细信息。
【讨论】:
【参考方案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 的图像的任何其他用途也是必要的。
【讨论】:
【参考方案4】:我不是专家,但我设法使用以下代码从 PIL 图像中获取了 opencv 图像:
import opencv
img = opencv.adaptors.PIL2Ipl(pilimg)
【讨论】:
以上是关于如何从 PIL 图像创建 OpenCV 图像?的主要内容,如果未能解决你的问题,请参考以下文章
在 Python 中将 openCV 图像转换为 PIL 图像(用于 Zbar 库)