Matlab调用OpenCV(C++)程序

  • Post author:
  • Post category:其他



本文以论文”

Zhang Q, Shen X, Xu L, et al. Rolling guidance filter[C]//European Conference on Computer Vision. Springer International Publishing, 2014: 815-830.

“提供的C++程序为例(依赖OpenCV),编写matlab调用OpenCV程序,使其可以用matlab运行,而且保持C++程序的快速性。


其中参考了博文


matlab调用C程序










Matlab与C++混合编程(依赖OpenCV)

。但是这两篇博文有些地方讲的不是很清楚,在接口函数中需要将数据首先从matlab读入进C++,然后经过C++函数运行有输出后,再将输出读出给matlab,这个过程是最重要的。





首先我把OpenCV放在了F盘,每次修改完.cpp文件后,都要使用matlab编译修改才可以生效,如果没有OpenCV的话,直接运行mex mexRollingGuidanceFilter.cpp就可以,但是有OpenCV后还需要加上它才可以,具体如下(具体的关于OpenCV与Visual Stdio的初始化连接就不介绍)







mex mexRollingGuidanceFilter.cpp -IF:\opencv\build\include -LF:\opencv\build\x64\vc10\lib -lopencv_core249 -lopencv_imgproc249 -lopencv_highgui249

然后是编写matlab调用主体函数,接口程序中调用的数据就来自这个函数,这个函数的名称没有特别要求,但是函数内部调用的C++函数名称必须和.cpp名称相同,具体如下






% /***************************************************************/
% /* Function: filter
% 	* 
% 	* Description: rolling guidance filter core code by using bilateral filter.
% 	* 
% 	* input arguments:
% 	*  img: input image. Accept CV_8U and CV_32F type. Accept any number of channels.
% 	*  sigma_s: spatial sigma (default 3.0). Controlling the spatial weight of bilateral filter and also the filtering scale of rolling guidance filter.
% 	*  sigma_r: range sigma (default 0.1). Controlling the range weight of bilateral filter.
% 	*  iteration: the iteration number of rolling guidance (default 4).
% 	*        
% 	*/
% /***************************************************************/

function out = RollingGuidanceFilter_C(img, sigma_s, sigma_r, iteration)

%     dim = ndims(img);
%     if(dim == 2)
%         out = mexRollingGuidanceFilter(img, sigma_s, sigma_r, iteration);
%         out = mat2gray(out);
%     elseif(dim == 3)
%         [R, G, B] = mexRollingGuidanceFilter(img, sigma_s, sigma_r, iteration);
%         out(:,:,1) = R;
%         out(:,:,2) = G;
%         out(:,:,3) = B;
%         out = mat2gray(out);
%     end

    dim = ndims(img);
    if(dim == 2)
        img2(:,:,1) = img;
        img2(:,:,2) = img;
        img2(:,:,3) = img;
        out = mexRollingGuidanceFilter(img2, sigma_s, sigma_r, iteration);%和.cpp文件名相同
        out = mat2gray(out);
    elseif(dim == 3)
        [R, G, B] = mexRollingGuidanceFilter(img, sigma_s, sigma_r, iteration);
        out(:,:,1) = R;
        out(:,:,2) = G;
        out(:,:,3) = B;
        out = mat2gray(out);
    end

接下来是C++文件mexRollingGuidanceFilter.cpp,在本来的C++文件中他只是一个正常的C++函数,这里把他的main()函数去掉,换成接口函数void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]),在接口函数中需要对数据在matlab和C++中进行相互读入与输出,上面的两篇博文在这里不是很细致,这里需要注意matlab存储图像矩阵的方式和C++存储图像矩阵的方式是不相同的,所以在指针传递数据的时候对应的位置会不相同,而且在用指针赋值时,格式稍有不对就会出错,具体如下






#include <cstdio>
#include <string>

#include <opencv/cv.h>  
#include "opencv2\core\core.hpp"
#include "opencv2\highgui\highgui.hpp"
#include "opencv2\imgproc\imgproc.hpp"
#include "permutohedral\macros.h"
#include "permutohedral\Image.h"
#include "permutohedral\permutohedral.h"



#include <time.h>
#include "mex.h"

//Use the namespace of CV and STD
using namespace std;
using namespace cv;

/***************************************************************/
/* Function: bilateralPermutohedral
	* 
	* Description: bilateral filter by using permutohedral lattice. Invoking the bilateral filter implementation provided on http://graphics.stanford.edu/papers/permutohedral/.
	* 
	* input arguments:
	*		  img: input image. Accept CV_32F type and any number of channels.
	*       edge: guidance image. Accept CV_32F type and any number of channels. 
	*	  sigma_s: spatial sigma (default 3.0). Controlling the spatial weight of bilateral filter.
	*    sigma_r: range sigma (default 0.1). Controlling the range weight of bilateral filter.
	*        
	*/
/***************************************************************/

Mat bilateralPermutohedral(Mat img, Mat edge, float sigma_s, float sigma_r){ // img: float [0,1]

	float invSpatialStdev = 1.0f/sigma_s;
	float invColorStdev = 1.0f/sigma_r;

	// Construct the position vectors out of x, y, r, g, and b.
	int height = img.rows;
	int width = img.cols;

	int eCh = edge.channels();
	int iCh = img.channels();
	Image positions(1, width, height, 2+eCh);
	Image input(1, width, height, iCh);

	//From Mat to Image
	for (int y = 0; y < height; y++) {
		float *pimg = img.ptr<float>(y);
		float *pedge = edge.ptr<float>(y);
		for (int x = 0; x < width; x++) {
			positions(x, y)[0] = invSpatialStdev * x;
			positions(x, y)[1] = invSpatialStdev * y;

			for(int c=0; c<eCh; c++)
				positions(x, y)[2+c] = invColorStdev * pedge[x*eCh+c];

			for(int c=0; c<iCh; c++)
				input(x, y)[c] = pimg[x*iCh+c];
		}
	}

	// Filter the input with respect to the position vectors. (see permutohedral.h)
	Image out = PermutohedralLattice::filter(input, positions);

	// Save the result
	Mat imgOut(img.size(), img.type());
	for (int y = 0; y < height; y++) {
		float *pimgOut = imgOut.ptr<float>(y);
		for (int x = 0; x < width; x++) {
			for(int c=0; c<iCh; c++)
				pimgOut[x*iCh+c] = out(x, y)[c];
		}
	}

	return imgOut;
}


/***************************************************************/
/* Function: filter
	* 
	* Description: rolling guidance filter core code by using bilateral filter.
	* 
	* input arguments:
	*		  img: input image. Accept CV_8U and CV_32F type. Accept any number of channels.
	*    sigma_s: spatial sigma (default 3.0). Controlling the spatial weight of bilateral filter and also the filtering scale of rolling guidance filter.
	*    sigma_r: range sigma (default 0.1). Controlling the range weight of bilateral filter.
	*  iteration: the iteration number of rolling guidance (default 4).
	*        
	*/
/***************************************************************/
// Mat RollingGuidanceFilter(Mat img, float sigma_s=3.0f, float sigma_r=0.1, int iteration=4)
Mat RollingGuidanceFilter(Mat img, float sigma_s, float sigma_r, int iteration)
{
		Mat I;
		
		//Change type to float
		img.convertTo(I,CV_MAKETYPE(CV_32F,img.channels()));

		Mat res = I.clone();

		// Filtering
		for(int i=0;i<iteration;i++){
			if(i)res = bilateralPermutohedral(I,res,sigma_s,sigma_r);
			else GaussianBlur(I,res,Size(0,0),sigma_s,sigma_s);
		}

		// Change type back
		res.convertTo(res,CV_MAKETYPE(img.depth(),img.channels()));

		return res;
	
}

// //单通道灰度图像接口函数
// void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
// {
//   
//     float sigma_s = mxGetScalar( prhs[ 1 ] );
//     float sigma_r = mxGetScalar( prhs[ 2 ] );
//     int iteration = mxGetScalar( prhs[ 3 ] );
//     
//     unsigned char *inData; 
//     inData = (unsigned char *)mxGetPr(prhs[0]); //获得指向输入矩阵的指针
//     int rows = mxGetM(prhs[0]); //获得输入矩阵的行数 
//     int cols = mxGetN(prhs[0]); //获得输入矩阵的列数 
//     
//     Mat image(rows,cols,CV_8UC1);
//     
//     for (int i = 0; i < rows; i++)  
//         for (int j = 0; j < cols; j++)  
//              image.at<uchar>(i, j) = *(inData + i + j * rows);
// 
//     Mat out;
//     out = RollingGuidanceFilter(image,sigma_s,sigma_r,iteration);
// 
//     plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
//     double *outData;   
//     outData = mxGetPr(plhs[0]);  
//     for (int i = 0; i < rows; i++)  
//         for (int j = 0; j < cols; j++)  
//              *(outData + i + j * rows) = (double)out.at<uchar>(i, j);
// }


// //三通道彩色图像接口函数
// void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
// {
//   
//     float sigma_s = mxGetScalar( prhs[ 1 ] );
//     float sigma_r = mxGetScalar( prhs[ 2 ] );
//     int iteration = mxGetScalar( prhs[ 3 ] );
//     
//     uchar *inData; 
//     uchar *InCurRow; 
//     inData = (uchar*)mxGetPr(prhs[0]); //获得指向输入矩阵的指针
//     int rows = mxGetM(prhs[0]); //获得输入矩阵的行数 
//     int cols = mxGetN(prhs[0]); //获得输入矩阵的列数 
//     int channel = mxGetNumberOfDimensions(prhs[0]);
//     cols = cols/channel;
// //     mexPrintf("rows is %i\n", rows);
//     
//     Mat image(rows,cols,CV_8UC3);//CV_8UC3
//     
//     for (int i = 0; i < rows; i++)
//     {
//         InCurRow = (uchar*)image.ptr<uchar>(i);//获取第i行的指针
//         for (int j = 0; j < cols; j++)  
//         {
//             for (int k = 0; k < channel; k++)
//             {
// //                   image.at<Vec3b>(i, j)[2 - k] = *(inData + i + j * rows + k * rows * cols);
// //                   InCurRow[j * channel + (2 - k)] = *(inData + i + j * rows + k * rows * cols);
//                   *(InCurRow + j * channel + (2 - k)) = *(inData + i + j * rows + k * rows * cols);
//             }
//         }
//     }
//     
//     Mat out(rows,cols,CV_8UC3);//CV_8UC3
//     out = RollingGuidanceFilter(image,sigma_s,sigma_r,iteration);
// 
//     plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
//     double *outData_R = mxGetPr(plhs[0]); 
//     plhs[1] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
//     double *outData_G = mxGetPr(plhs[1]); 
//     plhs[2] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
//     double *outData_B = mxGetPr(plhs[2]); 
//     
// 
//      for (int i = 0; i < rows; i++)
//     {
//         for (int j = 0; j < cols; j++)  
//         {
//             *(outData_R + i + j * rows) = (double)out.at<Vec3b>(i, j)[2];
//             *(outData_G + i + j * rows) = (double)out.at<Vec3b>(i, j)[1];
//             *(outData_B + i + j * rows) = (double)out.at<Vec3b>(i, j)[0];
//         }
//     } 
// }

// 灰度图和彩色图结合接口函数
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    //首先从matlab函数中读取数据作为C++函数RollingGuidanceFilter的输入
    float sigma_s = mxGetScalar( prhs[ 1 ] );
    float sigma_r = mxGetScalar( prhs[ 2 ] );
    int iteration = mxGetScalar( prhs[ 3 ] );
    
    uchar *inData = (uchar*)mxGetPr(prhs[0]); //获得指向输入矩阵的指针
    int rows = mxGetM(prhs[0]); //获得输入矩阵的行数 
    int cols = mxGetN(prhs[0]); //获得输入矩阵的列数 
    int channel = mxGetNumberOfDimensions(prhs[0]);//灰度图为2,彩色图为3
//     mexPrintf("channel is %i\n", channel);
    
    if(channel == 2)
    {
        Mat image(rows,cols,CV_8UC1);
        
        for (int i = 0; i < rows; i++)  
            for (int j = 0; j < cols; j++)  
                 image.at<uchar>(i, j) = *(inData + i + j * rows);

        Mat out;
        out = RollingGuidanceFilter(image,sigma_s,sigma_r,iteration);
       
        //通过运行RollingGuidanceFilter C++ 程序得到了输出,然后再将C++形式的输出out传给输出矩阵,使输出矩阵具有matlab形式
        plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
        double *outData;   
        outData = mxGetPr(plhs[0]);  
        for (int i = 0; i < rows; i++)  
            for (int j = 0; j < cols; j++)  
                 *(outData + i + j * rows) = (double)out.at<uchar>(i, j);
    }
    else
    {
    //     mexPrintf("rows is %i\n", rows);
        cols = cols/channel;
        Mat image(rows,cols,CV_8UC3);//CV_8UC3
        uchar *InCurRow;
        for (int i = 0; i < rows; i++)
        {
            InCurRow = (uchar*)image.ptr<uchar>(i);//获取第i行的指针
            for (int j = 0; j < cols; j++)  
            {
                for (int k = 0; k < channel; k++)
                {
    //                   image.at<Vec3b>(i, j)[2 - k] = *(inData + i + j * rows + k * rows * cols);
    //                   InCurRow[j * channel + (2 - k)] = *(inData + i + j * rows + k * rows * cols);
                      *(InCurRow + j * channel + (2 - k)) = *(inData + i + j * rows + k * rows * cols);
                }
            }
        }

        Mat out;//CV_8UC3
        out = RollingGuidanceFilter(image,sigma_s,sigma_r,iteration);

        plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
        double *outData_R = mxGetPr(plhs[0]); 
        plhs[1] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
        double *outData_G = mxGetPr(plhs[1]); 
        plhs[2] = mxCreateDoubleMatrix(rows, cols, mxREAL);  
        double *outData_B = mxGetPr(plhs[2]); 

         for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)  
            {
                *(outData_R + i + j * rows) = (double)out.at<Vec3b>(i, j)[2];
                *(outData_G + i + j * rows) = (double)out.at<Vec3b>(i, j)[1];
                *(outData_B + i + j * rows) = (double)out.at<Vec3b>(i, j)[0];
            }
        } 
    } 
}

matlab调用函数

clear all

img = imread('..\images\barbaraRGB.png');

tic
out = RollingGuidanceFilter_C(img,3,25.5,4);
toc

figure;imshow(out);

运行结果













版权声明:本文为majinlei121原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。