MSVS C# Matlab的混合编程系列2 - 构建一个复杂(含多个M文件)的动态库:

15 篇文章 3 订阅
10 篇文章 0 订阅

 前言:

本节我们尝试将一个有很多函数和文件的Matlab算法文件集成到C#的项目里面。

本文缩语:

MT = Matlab


问题提出:


1 我们有一个比较复杂的Matlab文件:

 这个MATLAB的算法,写了很多的算法函数在其他的M文件里面,这样,前面博客的方法就不够用了。会报错:

解决办法如下: 


写在前面的结论:

1 你要用一个外壳函数,封装你的最上层的M文件

2 去掉不必要的M文件间的耦合,把M文件的参数都写到 外壳函数上


 步骤:

1 编译:

1.1 常规操作: 多入口报错

 【报错】只能接受具有单个入口函数的 MATLAB 函数和 MEX 文件作为导出函数。未添加以下文件因为它们不是可接受的文件类型,或者包含在 MATLAB 根目录下: 

MT ,显然不支持多个入口函数的Matlab的源码:

【解决办法,封装成一个大函数】用一个function包起来就好了

function ballfitting(fname)
% Your code here
end

这里笔者,

1.1.1 还没有MT的输出参数的传递。

在MT命令行窗口调用deploytool

对C#的输出,MT里面我们选取如下: 

 1 using the Matlab .NET Assembly

 上图中,是没有MATLAB的输出参数的情况:但是,已经自动,把所有的MT相关的原文件都加了。

1.1.2 有MT的输出参数的传递的外壳函数封装。
function [centers,angle_degree] = findid_v1(filename)

... // your code

end

上面,

笔者给MT的外壳函数加了2个输出的的变量,和一个输入变量。

注意:外壳函数的现在的名称,findid_v1似乎没啥用,即使在C#调用,也没有用到。

然后,我们调用在MT中,命令行调用,deploytool,和前面一样。

 上图,自动,把所有的MT相关的原文件都加了的同时,大家应该注意到,

类MTFindid,多了两个输入的参数。

1.2 注意库的版本,最好每次更新M的原文件的时候,选择更新一下版本号


2 在C#中的调用步骤和方法:

2.1 在C#的项目中,

然后,调用就可以了。 在【项目】/【添加引用】

把上一小结,编译生成的动态库加入。

2.2 在C#的项目Frame中,,引入库

using MathWorks.MATLAB.NET.Arrays;
using find_id;
using MathWorks.MATLAB.NET.Utility;

2.3 真正的调用:
 注意!!!现在,我要开始讲到比较真正细节的解释接口编程了:

2.3.1 首先,我们要清楚,我们在MT做编译库的时候,做的类名和方法分别是什么:

                // Pass the file name to the dll.
                // lib name : find_id
                // Class name : MTFindid
                // Method name: find_id(filename)

 这里,我在上面,再单独列举了一下:

2.3.2 接口编写:

        private void button2_Click(object sender, EventArgs e)
        {

            // Create an instance of the open file dialog box.
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            // Set filter options and filter index.
            openFileDialog1.Filter = "PLY Files (.ply)|*.ply|All Files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;

            // Call the ShowDialog method to show the dialog box.
            DialogResult result = openFileDialog1.ShowDialog();

            // Process input if the user clicked OK.
            if (result == DialogResult.OK)
            {
                // Pass the file name to the dll.
                // lib name : find_id
                // Class name : MTFindid
                // Method name: find_id(filename)

                // Get the file name from the dialog box.
                string filename = openFileDialog1.FileName;

                // new object for class MTFindid
                find_id.MTFindid mtfdid = new find_id.MTFindid();

                // call the method
                mtfdid.find_id(2, filename);
            }

        }

 【Franlin案,详细解释,这段代码的最后两行,我在dll库find_id中,用库中的类结构MTFindid,申明了一个类的对象实例mtfdid,

然后,在源码的最后一行,我用对象mtfdid的方法find_id,调用MT库的外壳函数,

这个外壳函数,前面已经提到,有2个输出参数,一个文件名输入参数。

在上面的例子源码中,我已经给出了,输出参数,包括,C#中打开一个PLY图像,并把名字写入MT的dll的方法,下面,

我将详细讨论,MT dll如何在C#中,向C#传递输出参数。

 3 拿出Matlab里面的输出数据:

 【franklin案】要拿出Matlab的数据,MT 和 C# 两方面都需要修正:

3.1 matlab 中的修改

function [centers,angle_degree] = findid_v1(filename)

figure; imshow(segmented_img);

% Display centers and angles
disp('Centers:');
disp(centers);

disp('Angle Degree:');
disp(angle_degree);

return;
end

 上述,MT 函数,外壳函数findid_v1写了个两个输出的参数,[centers,angle_degree]

这点,其实前面已经说了。

3.2 C# 中进行拾取:

 private void button2_Click(object sender, EventArgs e)
        {


            // Create an instance of the open file dialog box.
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            // Set filter options and filter index.
            openFileDialog1.Filter = " BMP Files (.bmp)|*.bmp|PLY Files (.ply)|*.ply|All Files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;

            // Call the ShowDialog method to show the dialog box.
            DialogResult DialogResult = openFileDialog1.ShowDialog();

            // Process input if the user clicked OK.
            if (DialogResult == DialogResult.OK)
            {
                // Get the file name from the dialog box.
                string filename = openFileDialog1.FileName;

                // Pass the file name to the dll.
                // lib name : find_id
                // Class name : MTFindid
                // Method name: find_id(filename)

                // new object for class MTFindid
                find_id.MTFindid mtfdid = new find_id.MTFindid();

                // 不使用MT 返回值的调用
                mtfdid.find_id(2, filename);
                // 使用MT 返回值的调用
                MWArray[] result = mtfdid.find_id(2,filename);

                MWNumericArray centers = (MWNumericArray)result[0];
                double[,] centersData = (double[,])centers.ToArray(MWArrayComponent.Real);

                MWNumericArray angle_degree = (MWNumericArray)result[1];
                double[,] angle_degreeData = (double[,])angle_degree.ToArray(MWArrayComponent.Real);

            }

        }

上面是一段,已经编译验证过的,成功将MT 输出参数导出到 C# 的例子:

引入的库如上: 

解释几个有意思的东西:

3.2.1 MT dll的输入,输出的解释

                MWArray[] result = mtfdid.find_id(2,filename);

n the code MWArray[] result = obj.findid_v1(2, "your_file_path");, the number 2 represents the number of output arguments that the MATLAB function findid_v1 is expected to return.

In your MATLAB function definition function [centers,angle_degree] = findid_v1(filename), there are two output arguments: centers and angle_degree. Therefore, when calling this function from C#, you specify 2 as the first argument to indicate that you expect two outputs from the function.

The MWArray[] result will then be an array of MWArray objects, where result[0] corresponds to centers and result[1] corresponds to angle_degree. This allows you to access and use these results in your C# code.

3.2.2 MWArray的解释和使用:
3.2.2.1 首先,务必仔细处理好改通用动态库的版本和你的MT一致

我是直接在MT的安装位置找到的,

比如:

D:\Program Files\Polyspace\R2019b\toolbox\dotnetbuilder\bin\win64\v4.0\

 3.2.2.2 解释一下:
MWNumericArray centers = (MWNumericArray)result[0];
double[,] centersData = (double[,])centers.ToArray(MWArrayComponent.Real);

MWNumericArray angle_degree = (MWNumericArray)result[1];
double[,] angle_degreeData = 

MWNumericArray centers = (MWNumericArray)result[0];
出来是第一个MT输出参数,一个二维数组,centers

double[,] centersData = (double[,])centers.ToArray(MWArrayComponent.Real);

双精度格式转化

  3.2.2.3 为最终能用的格式:
  • 化为整形:
           int angledata = Convert.ToInt32(Math.Truncate(angle_degreeData[0, 0]));
  • 化为双精度:
                double angledata2 =Math.Truncate(angle_degreeData[0, 0]);


  4 如何显示出Matlab里面的图像数据:

【案,有两种从MT传递到C#的方法,1 通过内存的变量数组,2通过本地暂存的图片】

方法一,好处是,本地不留图片,问题是,会占用大量的内存,影响系统效率

方法二,保存为本地暂存图片,本文详述后一种方法:

 方法二,保存为图像:

% Display the grayscale image
figure; imshow(grayImage);

MT 源程序展示为figure,改为:

    imwrite(grayImage, 'grayImage.png');

这里,grayimage,就是个暂存的图片,他存哪里呢?

如果,我们是C#调用的话,比如,我的C#的工程设定 为:

那么,暂存的图片,会放在:

 笔者项目地址\bin\x64\Debug


遇到的问题:

文件再次打开的问题:

 解决Matlab,文件再次打开报错的问题:

1 笔者先增加一个表征图像情况的输出参数:

 2 MATLAB 增加判错的代码 :
% check the right to write
if newimage == 0
fid = fopen('grayImage.png', 'w');
if fid == -1 
    disp('Error: Unable to write to file grayImage.png.');
    newimage = 1;
else
    % Write to file
    imwrite(grayImage, 'grayImage.png');
    fclose(fid);
    newimage = 0;
end
end

if newimage == 1
    fid2 = fopen('grayImage_1.png', 'w');
    if fid2 == -1
        disp('Error: Unable to write to file grayImage_1.png.');
        newimage = 0;
    else
    % Write to file
        imwrite(grayImage, 'grayImage_1.png');
        fclose(fid2);
        newimage = 1;
    end
end

【案,这段代码,笔者每次写暂存图像文件之前,都尝试打开这个文件,如果,这个文件目前不能被开,那么是被占用了,我们存到另外一个暂存文件,并以此反复,这样,

C#中,即使不小心打开两次,一般都没有问题,这样MT的处理的图像就可以在C#中,你在利用C#的图形工具打开即可】

                // show the pictures 
                if (fileopenFlag == 0)
                {
                    pictureBox1.Image = Image.FromFile("grayImage.png");
                }
                else
                {
                    pictureBox1.Image = Image.FromFile("grayImage_1.png");
                }
                // Get the Graphics object from the Reading image
                Graphics graphics = Graphics.FromImage(pictureBox1.Image);

下面,这段C#的代码,就是配合MT来对暂存的图片进行展示的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Franklin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值