我在Matlab中有一张图片:
img = imopen('image.jpg')
返回uint8数组高度x宽x通道(3通道:RGB)。
现在我想使用openCV对它进行一些操作,所以我写了一个MEX文件,它将图像作为参数并从中构造一个IplImage:
#include "mex.h"
#include "cv.h"
void mexFunction(int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs) {
char *matlabImage = (char *)mxGetData(prhs[0]);
const mwSize *dim = mxGetDimensions(prhs[0]);
CvSize size;
size.height = dim[0];
size.width = dim[1];
IplImage *iplImage = cvCreateImageHeader(size, IPL_DEPTH_8U, dim[2]);
iplImage->imageData = matlabImage;
iplImage->imageDataOrigin = iplImage->imageData;
/* Show the openCV image */
cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
cvShowImage("mainWin", iplImage);
}
这个结果看起来完全错误,因为openCV使用除matlab之外的其他约定来存储图像(例如,它们交错颜色通道)。
任何人都可以解释约定的差异,并就如何正确显示图像提供一些指示吗?
答案 0 :(得分:12)
花了一天时间进行有趣的图片格式转换</sarcasm>
我现在可以回答我自己的问题了。
Matlab将图像存储为三维数组:高度×宽度×颜色
OpenCV将图像存储为二维数组:(颜色×宽度)×高度
此外,为了获得最佳性能,OpenCV用零填充图像,因此行总是在32位块上对齐。
我在Matlab中完成了转换:
function [cv_img, dim, depth, width_step] = convert_to_cv(img)
% Exchange rows and columns (handles 3D cases as well)
img2 = permute( img(:,end:-1:1,:), [2 1 3] );
dim = [size(img2,1), size(img2,2)];
% Convert double precision to single precision if necessary
if( isa(img2, 'double') )
img2 = single(img2);
end
% Determine image depth
if( ndims(img2) == 3 && size(img2,3) == 3 )
depth = 3;
else
depth = 1;
end
% Handle color images
if(depth == 3 )
% Switch from RGB to BGR
img2(:,:,[3 2 1]) = img2;
% Interleave the colors
img2 = reshape( permute(img2, [3 1 2]), [size(img2,1)*size(img2,3) size(img2,2)] );
end
% Pad the image
width_step = size(img2,1) + mod( size(img2,1), 4 );
img3 = uint8(zeros(width_step, size(img2,2)));
img3(1:size(img2,1), 1:size(img2,2)) = img2;
cv_img = img3;
% Output to openCV
cv_display(cv_img, dim, depth, width_step);
将其转换为IplImage的代码位于MEX文件中:
#include "mex.h"
#include "cv.h"
#include "highgui.h"
#define IN_IMAGE prhs[0]
#define IN_DIMENSIONS prhs[1]
#define IN_DEPTH prhs[2]
#define IN_WIDTH_STEP prhs[3]
void mexFunction(int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs) {
bool intInput = true;
if(nrhs != 4)
mexErrMsgTxt("Usage: cv_disp(image, dimensions, depth, width_step)");
if( mxIsUint8(IN_IMAGE) )
intInput = true;
else if( mxIsSingle(IN_IMAGE) )
intInput = false;
else
mexErrMsgTxt("Input should be a matrix of uint8 or single precision floats.");
if( mxGetNumberOfElements(IN_DIMENSIONS) != 2 )
mexErrMsgTxt("Dimension vector should contain two elements: [width, height].");
char *matlabImage = (char *)mxGetData(IN_IMAGE);
double *imgSize = mxGetPr(IN_DIMENSIONS);
size_t width = (size_t) imgSize[0];
size_t height = (size_t) imgSize[1];
size_t depth = (size_t) *mxGetPr(IN_DEPTH);
size_t widthStep = (size_t) *mxGetPr(IN_WIDTH_STEP) * (intInput ? sizeof(unsigned char):sizeof(float));
CvSize size;
size.height = height;
size.width = width;
IplImage *iplImage = cvCreateImageHeader(size, intInput ? IPL_DEPTH_8U:IPL_DEPTH_32F, depth);
iplImage->imageData = matlabImage;
iplImage->widthStep = widthStep;
iplImage->imageDataOrigin = iplImage->imageData;
/* Show the openCV image */
cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
cvShowImage("mainWin", iplImage);
}
答案 1 :(得分:1)
您可以使用mxGetDimensions和mxGetNumberOfDimensions优化程序以获取图像的大小,并使用mxGetClassID更准确地确定深度。
我想做同样的事情,但我认为使用matlab dll和calllib这样做会更好。我不会在opencv格式中进行图像转换而不是matlab,因为它会很慢。这是matlab openCV最大的问题之一。我认为opencv2.2有一些很好的解决方案。看起来有一些像opencv社区那样的八度音程解决方案,但我仍然不理解它们。它们以某种方式使用opencv的c ++功能。
答案 2 :(得分:1)
尝试使用由Kota Yamaguchi开发的库: http://github.com/kyamagu/mexopencv 它定义了一个名为“MxArray”的类,它可以执行从MATLAB mxArray变量到OpenCV对象(以及从OpenCV到MATLAB)的所有类型的转换。例如,此库可以在mxArray和cv :: Mat数据类型之间进行转换。顺便说一下,如果你使用OpenCV的C ++ API,IplImage就不再相关了,最好使用cv :: Mat。
注意:如果使用该库,请确保从库中编译带有 MxArray.cpp文件的mex函数;您可以在MATLAB命令行中执行以下操作:
mex yourmexfile.cpp MxArray.cpp
答案 3 :(得分:1)
根据答案和How the image matrix is stored in the memory on OpenCV,我们只能使用Opencv Mat操作!
C++: Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0)
C++: void merge(const Mat* mv, size_t count, OutputArray dst)
然后mex C / C ++代码是:
#include "mex.h"
#include <opencv2/opencv.hpp>
#define uint8 unsigned char
void mexFunction(int nlhs, mxArray *out[], int nrhs, const mxArray *input[])
{
// assume the type of image is uint8
if(!mxIsClass(input[0], "uint8"))
{
mexErrMsgTxt("Only image arrays of the UINT8 class are allowed.");
return;
}
uint8* rgb = (uint8*) mxGetPr(input[0]);
int* dims = (int*) mxGetDimensions(input[0]);
int height = dims[0];
int width = dims[1];
int imsize = height * width;
cv::Mat imR(1, imsize, cv::DataType<uint8>::type, rgb);
cv::Mat imG(1, imsize, cv::DataType<uint8>::type, rgb+imsize);
cv::Mat imB(1, imsize, cv::DataType<uint8>::type, rgb+imsize + imsize);
// opencv is BGR and matlab is column-major order
cv::Mat imA[3];
imA[2] = imR.reshape(1,width).t();
imA[1] = imG.reshape(1,width).t();
imA[0] = imB.reshape(1,width).t();
// done! imf is what we want!
cv::Mat imf;
merge(imA,3,imf);
}