本文以论文”
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);
运行结果