python 如何从 PIL 图像创建 OpenCV 图像?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1650568/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:48:10  来源:igfitidea点击:

How do I create an OpenCV image from a PIL image?

pythonimage-processingopencvpython-imaging-library

提问by Arkady

I want to do some image processing with OpenCV (in Python), but I have to start with a PIL Imageobject, so I can't use the cvLoadImage()call, since that takes a filename.

我想用 OpenCV(在 Python 中)做一些图像处理,但我必须从一个 PILImage对象开始,所以我不能使用cvLoadImage()调用,因为它需要一个文件名。

This recipe (adapted from http://opencv.willowgarage.com/wiki/PythonInterface) does not work because cvSetDatacomplains argument 2 of type 'void *'. Any ideas?

这个秘籍(改编自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)) 

I think the last argument to the cvSetDatais wrong too, but I am not sure what it should be.

我认为最后一个论点cvSetData也是错误的,但我不确定它应该是什么。

回答by Frederic De Groef

The example you tried to adapt is for the new python interface for OpenCV 2.0. This is probably the source of the confusion between the prefixed and non-prefixed function names (cv.cvSetData()versus cv.SetData()).

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

OpenCV 2.0 now ships with two sets of python bindings:

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

  • The "old-style" python wrapper, a python package with the opencv.{cv,highgui,ml}modules
  • The new interface, a python C extension (cv.pyd), which wraps all the OpenCV functionalities (including the highguiand mlmodules.)
  • “旧式” Python包装,Python包与opencv.{cv,highgui,ml}模块
  • 新的接口,一个python C扩展(cv.pyd),它包装所有OpenCV的官能团(包括highguiml模块)。

The reason behind the error message is that the SWIG wrapper does not handle conversion from a python string to a plain-old C buffer. However, the SWIG wrapper comes with the opencv.adaptorsmodule, which is designed to support conversions from numpyand PILimages to OpenCV.

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

The following (tested) code should solve your original problem (conversion from PIL to OpenCV), using the SWIG interface :

以下(经过测试的)代码应该使用 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)

However, this does not solve the fact that the cv.cvSetData()function will always fail (with the current SWIG wrapper implementation). You could then use the new-style wrapper, which allows you to use the cv.SetData()function as you would expect :

但是,这并不能解决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)

A third approach would be to switch your OpenCV python interface to the ctypes-based wrapper. It comes with utility functions for explicit data conversion between e.g. python strings and C buffers. A quick look on google code searchseems to indicate that this is a working method.

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

Concerning the third parameter of the cvSetData()function, size of the image buffer, but the image step. The step is the number of bytes in one row of your image, which is pixel_depth * number_of_channels * image_width. The pixel_depthparameter is the size in bytes of the data associated to one channel. In your example, it would be simply the image width (only one channel, one byte per pixel).

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

回答by Dingle

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.

同时拥有 swig 和 new python 绑定真的很令人困惑。例如,在 OpenCV 2.0 中,cmake 可以接受 BUILD_SWIG_PYTHON_SUPPORT 和 BUILD_NEW_PYTHON_SUPPORT。但无论如何,我有点想通了大多数陷阱。

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

在使用“import cv”(新的python 绑定)的情况下,还需要一个步骤。

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.

RGB 图像需要转换,因为 PIL 和 IplImage 中的序列不同。这同样适用于 Ipl 到 PIL。

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

但是如果你使用 opencv.adaptors,它已经被处理了。如果有兴趣,您可以查看 adapters.py 中的详细信息。

回答by Martin

I did this using the python2.6 bindings of OpenCV2.1:

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

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

The image rotation and reversion of the string is to swap RGB into BGR, that is used in OpenCV video encoding. I assume that this would also be necessary for any other use of an image converted from PIL to OpenCV.

字符串的图像旋转和反转是将RGB 交换为BGR,用于OpenCV 视频编码。我认为这对于从 PIL 转换为 OpenCV 的图像的任何其他用途也是必要的。

回答by crodas

I'm not an expert but I managed to get a opencv image from a PIL image with this code:

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

import opencv

img = opencv.adaptors.PIL2Ipl(pilimg)