win7 x64下,matlab2016的均值滤波m文件转成vs2013 cpp dll,cpp调用实例

开发运行环境说明:
win7 x64、matlab2016、均值滤波、m文件、转成vs2013 cpp dll、cpp调用实例。
qt5.5.1 64位。vs cpp工程为64位。因为matlab2016只提供m文件对应的64位的dll。

开发过程中遇到的坑:
1、网上找的matlab均值滤波m文件是有问题的。问题在于它假定输入的3*1的矩阵,注释也不清楚,窗口大小用n表示,数据用array表示,我一开始一直以为n是标识array的size。
为了解决这个坑,只好自己学习matlab的m语言语法(学了一点,够解决当前问题即可)。均值滤波也是从零开始学(其实蛮简单)。
2、自己写的均值滤波m文件,在matlab中调试运行,结果是正常的浮点数。m转成dll后,通过cpp调用获得的结果却是整形值。
原因查了很久,最终定位到:matlab转m为cpp dll存在一个默认类型问题。感觉这算matlab的一个bug。
解决办法:m代码中将除数、被除数强行转换为double再相除。其实哪些该强转,哪些可以不强转,我也不清楚,一律强转后,输出正常了,也就未详细测试了。

对1*n矩阵进行均值滤波的m文件如下:

function [OutResult,error_msg] =junzhi(double_vec,win_size)
OutResult=double(double_vec);              %转换后的数据赋给OutResult
error_msg='null';                          %默认错误信息为null
if (win_size<3)
    error_msg='error:win_size < 3.';
    return;                                %窗口值357...
end
[row_count, col_count]=size(double_vec);   %获取矩阵大小,row_count一般为1。win_size窗口大小一般为奇数357
if (row_count > 1)
    error_msg='error:row_count > 1.';
    return;                                %只处理一维浮点数
end
if (col_count < win_size)
    error_msg='error:col_count < win_size.';
    return;                                %浮点数总数不得小于窗口大小
end
%
double_vec1=double(double_vec);            %数据类型转换
win_half=(win_size-1)/2;                   %窗口半径
d_win_size = double(win_size);             %用于double除法,用win_size除可能会得到整数
d_win_half = double(win_half);             %用于double除法

%return;                                   %直接返回可以获得浮点数返回值。说明后面如果返回整数值,原因是处理过程中类型转换出了问题。

for j=1:win_half                           %数组最前面的数,计算均值
    c=double_vec1(1,1:j+win_half);         %在double_vec1中取窗口大小的块赋给c
    s=double(sum(c));                      %取一行的和,转换为double,否则可能为整数
    OutResult(1,j)=s/double(j+d_win_half); %将模板各元素的均值赋给模板中心位置的元素  
end

for j=(1+win_half):(col_count-win_half)     %数组中间的数,计算均值
    c=double_vec1(1,j-win_half:j+win_half); %在double_vec1中取窗口大小的块赋给c
    s=double(sum(c));                       %取一行的和,转换为double,否则可能为整数
    OutResult(1,j)=s/d_win_size;            %将模板各元素的均值赋给模板中心位置的元素  
end

for j=(col_count-win_half+1):(col_count)               %数组最后面的数,计算均值
    c=double_vec1(1,j-win_half:col_count);             %在double_vec1中取窗口大小的块赋给c
    s=double(sum(c));                                  %取一行的和,转换为double,否则可能为整数
    OutResult(1,j)=s/double(col_count-j+win_half+1);   %将模板各元素的均值赋给模板中心位置的元素  
end

实际上cpp中1 * n矩阵就是double的vector。我这个不针对图像,所以没有3 * 3这种窗口,窗口是一维数轴上的窗口。

matlab转换为cpp dll后,h文件中关键接口如下:

extern LIB_junzhi_CPP_API void MW_CALL_CONV junzhi(int nargout, mwArray& OutResult, mwArray& error_msg, const mwArray& double_vec, const mwArray& win_size);

cpp调用代码:

bool data_process::junzhi_m(const int iOut, std::string &error_msg,
    double_vec &dVecOut, double_vec &dVecIn, const int iWinSize)
{
    //junzhi(int nargout, mwArray& OutResult, mwArray& error_msg, const mwArray& double_vec, const mwArray& win_size);
    if (!initialize_junzhi())
    {
        return false;
    }
    //iOut一般为1。此处加了error_msg,所以为2.
    dVecOut.resize(dVecIn.size());//dVecOut输出参数与输入大小一样
    //dVecIn输入参数一般为浮点数数组
    //iWinSize均值滤波的窗口大小,一般为奇数3、5、7...
    try
    {
        mwArray out_ptr(1, dVecOut.size(), mxDOUBLE_CLASS, mxREAL);
        out_ptr.SetData(&(dVecOut[0]), dVecOut.size());//输出数据缓存赋值
        //
        mwArray in_ptr(1, dVecIn.size(), mxDOUBLE_CLASS, mxREAL);
        in_ptr.SetData(&(dVecIn[0]), dVecIn.size());//输入数据缓存赋值
        //
        mwArray win_size_ptr(1, 1, mxINT32_CLASS, mxREAL);
        int data1[1] = { iWinSize };//均值窗口大小
        win_size_ptr.SetData(data1, 1);//窗口大小参数赋值
        //
        char *pcT = NULL;
        mwArray error_msg_ptr(pcT);//错误信息
        //
        ::junzhi(iOut, out_ptr, error_msg_ptr, in_ptr, win_size_ptr);//进入M dll处理
        out_ptr.GetData((mxDouble*)(&(dVecOut[0])), dVecOut.size());//取出返回值,浮点数都变为整数了
        error_msg = error_msg_ptr.ToString();//错误信息,null表示无错误
        if (error_msg != "null")
        {
            return false;
        }
    }
    catch (std::exception &e)
    {
        GuiLog("[ERROR]data_process::junzhi_m error.");
        GuiLog(CodePageInfor::LocalToUtf8(e.what()));
        return false;
    }
    return true;
}

初始化函数initialize_junzhi相关的环境初始化和终止:

bool data_process::initialize_junzhi()
{
    if (!initialize_matlab())
    {
        return false;
    }
    if (!b_init_junzhi)
    {
        GuiLog("junzhiInitialize ......");
        if (!junzhiInitialize())
        {
            GuiLog("junzhiInitialize error.");
            return false;
        }
        else
        {
            GuiLog("junzhiInitialize ok.");
        }
        b_init_junzhi = true;
    }
    return true;
}

bool data_process::initialize_matlab()
{
    if (!b_init_matlab)
    {
        if (!mclmcrInitialize())
        {
            GuiLog("mclmcrInitialize error.");
            return false;
        }
        else
        {
            GuiLog("mclmcrInitialize ok.");
        }
        if (!mclInitializeApplication(NULL, 0))
        {
            GuiLog("mclInitializeApplication error.");
            return false;
        }
        else
        {
            GuiLog("mclInitializeApplication ok.");
        }
        b_init_matlab = true;
    }
    return true;
}

bool data_process::terminate_matlab()
{
    terminate_junzhi();
    if (b_init_matlab)
    {
        if (!mclTerminateApplication())
        {
            GuiLog("mclTerminateApplication error.");
            return false;
        }
        else
        {
            GuiLog("mclTerminateApplication ok.");
        }
        b_init_matlab = false;
    }
    return true;
}

bool data_process::terminate_junzhi()
{
    if (b_init_junzhi)
    {
        junzhiTerminate();
        b_init_junzhi = false;
    }
    return true;
}

junzhi_m的调用代码:


typedef std::vector<double> double_vec;
        double_vec &vOut = get_mem_data_after()->val_vec_;
        double_vec &vIn = get_mem_data_original()->val_vec_;
        language_type lan_t = p_process->get_lan_type();
if (kLT_M == lan_t)
        {
            std::string error_msg;
            bool b = data_process::junzhi_m(2, error_msg, vOut, vIn, p_process->get_win_size());
            if (b)
            {
                GuiLog("data_process::junzhi_m ok.");
            }
            else
            {
                GuiLog("[ERROR]data_process::junzhi_m error:" + error_msg);
            }
        }

c语言版本的均值滤波代码:

bool data_process::junzhi_c(double_vec &dVecOut, double_vec &dVecIn, const int iWinSize)
{
    //窗口大小iWinSize一般为奇数,3、5、7...
    //假定窗口为奇数x,当前数据下标i,那么最左边元素下标i-(x-1)/2,最右边元素下标i+(x-1)/2
    //下标i处理后的值由元素[i-(x-1)/2,i+(x-1)/2]总和除以x。越界下标不统计。
    //窗口为3时,0下标由0、1求平均值,1下标由0、1、2求平均值...最后一个由倒数2个求。
    //窗口大小0无效、1就是不处理、2不处理、3有效、4与3结果一致
    int half_win = (iWinSize - 1) / 2;//窗口半径大小,取整
    if (half_win <= 0)
    {
        dVecOut = dVecIn;
        return true;
    }
    int iInSize = dVecIn.size();
    dVecOut.resize(iInSize);
    for (int i = 0; i < iInSize; ++i)
    {
        int iLeft = i - half_win;//窗口左值
        int iRight = i + half_win;//窗口右值
        double dSum = 0;//累加值
        int iSumCount = 0;//累加个数统计
        for (int j = iLeft; j <= iRight; ++j)
        {
            if (j >= 0 && j < iInSize)//窗口内有效下标
            {
                dSum += dVecIn[j];
                ++iSumCount;//实际累加的个数
            }
        }
        dVecOut[i] = dSum / iSumCount;//均值
    }
    return true;
}

c语言版本的调用代码:

        if (kLT_C == lan_t)
        {
            bool b = data_process::junzhi_c(vOut, vIn, p_process->get_win_size());
            if (b)
            {
                GuiLog("data_process::junzhi_c ok.");
            }
            else
            {
                GuiLog("[ERROR]data_process::junzhi_c error.");
            }
        }

猜你喜欢

转载自blog.csdn.net/weixin_43172531/article/details/104034978
cpp