如何将OpenCV的cvMat转换回NumPy的ndarray?
我在使用OpenCV的Python手册中的代码,想把cvMat转换成numpy数组:
mat = cv.CreateMat(3,5,cv.CV_32FC1)
cv.Set(mat,7)
a = np.asarray(mat)
但是在我电脑上用的是OpenCV 2.1,这个方法不管用。这里的结果a是一个对象数组,使用"print a"的时候,不能显示a里的所有元素,只能显示<cvmat(type=42424005 rows=3 cols=5 step=20 )>
。那么,怎么才能把一个OpenCV Mat对象完整地转换成原来的numpy.ndarray对象呢?
3 个回答
2
你说得对,这个食谱里的例子对我也不管用,我得到的结果和你的一样(我用的是win xp,python 2.6.6,opencv 2.1,numpy 1.5.1)。
也许你可以试试类似下面的代码:
>>> mat = cv.CreateMat(3,5,cv.CV_32FC1)
>>> cv.Set(mat,7)
>>> mylist = [[mat[i,j] for i in range(3)] for j in range(5)]
>>> ar = np.array(mylist)
>>> ar
array([[ 7., 7., 7.],
[ 7., 7., 7.],
[ 7., 7., 7.],
[ 7., 7., 7.],
[ 7., 7., 7.]])
2
对于OpenCV的2.1版本,如果你想要共享内存,并且不介意写一点C语言代码和使用SWIG工具,你可以试试我之前用过的这个方法:
CvMat * npymat_as_cvmat_32f(float * npymat_float, int rows, int cols)
{
CvMat * cvmat;
cvmat = cvCreateMatHeader(rows, cols, CV_32FC1);
cvSetData(cvmat, npymat_float, cols * sizeof(float));
return cvmat;
}
首先,创建一个头文件,比如叫mat_conversion.h:
/* npymat_as_cvmat_32f
*
* Create an OpenCV CvMat that shared its data with the input NumPy double array
*/
CvMat * npymat_as_cvmat_32f(float * npymat_float, int rows, int cols);
然后,创建一个接口文件(numpy_meets_opencv.i):
/* numpy_meets_opencv */
%module numpy_meets_opencv
%{
#define SWIG_FILE_WITH_INIT
#include <cv.h>
#include "mat_conversion.h"
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (float* INPLACE_ARRAY2, int DIM1, int DIM2) {(float* npymat_float, int rows, int cols)};
%include "mat_conversion.h"
接下来,进行编译:
numpy_meets_opencv: numpy_meets_opencv.i mat_conversion.c
swig -python -classic numpy_meets_opencv.i
$(CC) $(NPY_CFLAGS) -fPIC -fno-stack-protector -c mat_conversion.c `pkg-config --cflags $(PKGS)`
$(CC) $(NPY_CFLAGS) -fPIC -fno-stack-protector -c numpy_meets_opencv_wrap.c `pkg-config --cflags $(PKGS)`
ld -shared mat_conversion.o numpy_meets_opencv_wrap.o `pkg-config --libs $(PKGS)` -o _numpy_meets_opencv.so
最后,你就可以开始你的工作了:
In [1]: import numpy_meets_opencv as npyocv
In [2]: import opencv as cv
In [4]: import numpy as npy
In [12]: Inpy = npy.zeros((5,5), dtype=npy.float32)
In [13]: Iocv = npyocv.npymat_as_cvmat_32f(Inpy)
In [14]: Inpy
Out[14]:
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]], dtype=float32)
In [15]: Iocv
Out[15]: <opencv.cv.CvMat; proxy of <Swig Object of type 'CvMat *' at 0x30e6ed0> >
In [17]: cv.cvSetReal2D(Iocv, 3,3, 255)
In [18]: Inpy
Out[18]:
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 255., 0.],
[ 0., 0., 0., 0., 0.]], dtype=float32)
9
试着在你的矩阵后面加上 [:,:]
,也就是说在调用 np.asarray
时用 mat[:,:]
代替 mat
。这样做可以让 asarray
也能处理图像。
你的例子:
>>> import cv
>>> import numpy as np
>>> mat = cv.CreateMat( 3 , 5 , cv.CV_32FC1 )
>>> cv.Set( mat , 7 )
>>> a = np.asarray( mat[:,:] )
>>> a
array([[ 7., 7., 7., 7., 7.],
[ 7., 7., 7., 7., 7.],
[ 7., 7., 7., 7., 7.]], dtype=float32)
还有对于图像:
>>> im = cv.CreateImage( ( 5 , 5 ) , 8 , 1 )
>>> cv.Set( im , 100 )
>>> im_array = np.asarray( im )
>>> im_array
array(<iplimage(nChannels=1 width=5 height=5 widthStep=8 )>, dtype=object)
>>> im_array = np.asarray( im[:,:] )
>>> im_array
array([[100, 100, 100, 100, 100],
[100, 100, 100, 100, 100],
[100, 100, 100, 100, 100],
[100, 100, 100, 100, 100],
[100, 100, 100, 100, 100]], dtype=uint8)