zoukankan      html  css  js  c++  java
  • 在C# Winform程序中调用Matlab作多个图像

    1. 概述
      本文主要解决以下几个问题:

      1. Matlab函数生成Dll;
      2. 在C#程序中调用生成的dll;
      3. 程序中需要同时显示多个Figure时的处理。
    2. 问题背景
      工作中遇到在winform中作3维点云图的需求,网上翻阅了很多资料无果,最终无奈选择使用matlab作图,将matlab的figure嵌入到程序窗体中。
      由于存在同时显示多个图像的需求,网上有将图像窗口嵌入程序中的方法,但没有找到同时使用多个figure的情况,为此做了一些尝试,将尝试的过程做简单记录。
      测试过程中发现使用matlab的图像窗口会导致程序内存占用上升较多,特别是使用多个图像窗口时,所以以后如果能找到替代方法,预计会将这种做法废弃。
      本文中用到的方法其实不局限于winform程序。

    3. Matlab函数生成Dll

      • 环境:Matlab r2020a
      • 函数:
      % 函数作用:根据传入的一维数组,画3维点云图
      function [] = draw(xyz)
      figure()
      % 将一维数组转换成3*n并转置,因为点云是由一些(x,y,z)坐标的点构成
      a = reshape(xyz, 3, length(xyz) / 3).';
      % 转换为点云类型
      p = pointCloud(b);
      % 这是一个专门用来作点云图的方法
      % 听说如果是4维的数据的话,第4维可以用来指定颜色,如果没有指定颜色的话,默认渲染出来的彩图颜色还挺好看的
      pcshow(p);
      
      • dll生成步骤:
        命令行输入deploytool->选择Library Compiler->选择.Net Assembly->增加函数文件->修改className->选择Package->选择生成的文件夹for_redistribution_files_only中的dll文件,我使用的是没有Native后缀的文件。

    4. C#程序中调用Dll
      程序引用中添加Com组件,选择Matlab Appliaction Type Library;

      浏览,添加MWArray.dll,我的这个dll的路径在C:/Windows/Microsoft.Net/assembly/GAC_MSIL/MWArray下面,这边注意要根据是32位程序还是64位程序作出选择,我的程序是AnyCpu;
      添加上一步骤中生成的dll的引用;
      程序中增加对上面两个dll的using。
      使用时:以我上面的函数为例,

      Draw draw = new Draw();
      // int[]类型需要转换为MWNumericArray
      draw.draw((MWNumericArray)new int[] { 0, 0, 0});
      

      注意:此处的Draw是IDisposable的,用完之后一定要Dispose掉,new出来并使用的Draw对象越多,占用的内存越大,这个东西占用的内存还是很大的。

    5. 多个图同时显示并存在特定的刷新需求
      这个问题其实是我本篇中所要解决的最主要的问题,上面所说的这些内容都是可以在网上找到参考事项的,关于如何在winform程序中捕获到调用matlab函数生成的figure不做过多赘述,有需求可以参考文末的参考链接。

      • 解决这个问题有以下几个点需要注意或会用到:
      1. 每次调用figure会生成一个新的figure,如果不在figure的时候做出限制,figure的标题将按照顺序递增,依次为figure 1,figure 2,figure 3...
      2. 如果关闭figure,将会重新开始计数;
      3. 使用figure('toolbar', 'none', 'menubar', 'none', "name", name, 'numberTitle', 'off'); 对"name"属性和"numberTitle"属性做出限制,可以将标题中的figure n删除,并指定标题名称,"toolbar"和"menubar"属性用来关闭菜单;
      4. clf可以清除图上的内容;
      5. findobj('Type', 'figure')函数可以用来找到当前打开的所有figure,返回值是一个数组。
      • 具体要求:
      1. 同时打开多个figure;
      2. 随机可能需要刷新第n个figure上的图像。
      • 解决这个问题我尝试了以下思路:(本人非专业使用matlab,只是曾经使用过,可能有一些简便方法我不知道)
      1. 先说如果只有一个figure的情况,可以加一个flag,表明当前是否需要生成新的figure,只在需要生成新的figure的时候调用figure函数,否则调用clf函数清空已作图像;
      2. 在需要刷新的时候,生成一个新的figure,并调用user32中的SendMessage接口,将上一个窗口关闭,此前需要获取到上一个窗口的句柄,
        这种做法的问题在于窗口的闪烁非常严重,因为本来就涉及到捕获窗口的问题,figure窗口刚刚出来的时候其实是独立于我的程序界面的,很容易能够看到窗口一闪而过,而且经常会出现窗口嵌入我的程序中时窗口大小不一致,窗口很混乱,有时候能正常显示,有时候显示的数量不足,某些窗口没有显示出来,这个可能和找到的窗口句柄有关系。
        这种做法的主要思想就是找到窗口句柄,关闭不需要的窗口,以此为蓝本,我希望能够将当前的窗口句柄作为参数传入接口中,接口函数中直接将图作在拥有指定句柄的图形窗口中,然而,matlab中的窗口句柄与我通过user32获取到的窗口句柄有所不同,matlab中的窗口句柄更像是一个对象,而user32获取到的窗口句柄是int型的。通过不断尝试,终于找到了下面的方法:
      3. 为figure分配id,在调用函数的时候将id作为传入参数,以id作为figure的name,使用findobj函数查找所有已经打开的figure,根据figure.Name属性判断是否有和传入的name参数一致的figure,如果有则清空对应的figure,否则则创建新的figure
    6. 参考:C#调用Matlab画图,figure嵌入到Winform窗体

  • 相关阅读:
    Android控件之ListView探究二
    解决activity页面跳转时显示桌面
    TextView实现滚动显示的效果
    QPainter的坐标系系统的转换
    MODBUS_RTU通信协议
    收藏的博客 -- Qt有关的GitHub/Gitee开源项目
    VS联调多个解决方案的项目
    软件工具——GitGUI使用教程
    Python中对文件的操作
    VMware虚拟机三种网络模式详解 --------- NAT(地址转换模式)
  • 原文地址:https://www.cnblogs.com/yutou2016/p/14191731.html
Copyright © 2011-2022 走看看