Использование .Net библиотек в MATLAB

в 6:32, , рубрики: .net, Matlab, интеграция, Песочница, метки: , ,

Привет Хабровчанам! На Хабре уже обсуждался вопрос интеграции .Net c Matlab'ом. Цель же этой статьи — показать, как можно быстро и удобно решить обратную задачу: вызывать управляемый код из произвольных .Net библиотек в Matlab.

Зачем это нужно?

Несмотря на богатый набор алгоритмов в функционале Matlab'а, основным сценарием, в котором это может понадобиться, является необходимость задействовать в вычислениях уже имеющиеся и обладающие известными показателями качества .Net библиотеки, в которых реализованы математические алгоритмы.

Disclaimer

Пример, который рассматривается в статье, описывает типичный набор случаев возникающих при интеграции, достаточный для проведения широкого класса вычислений, однако, не охватывает всех возможностей интеграции с .Net, которые присутствуют в Matlab.
Код из данной статьи был сделан и протестирован на Windows платформе и в конкретной версии Matlab 2013a. В качестве версии .Net Framework использовалась 4.5, IDE — VS 2012.

Создание объектов .Net в Matlab

В качестве простого примера рассмотрим создание объекта стандартного класса DateTime из .Net.
Получение текущей даты-времени из .Net может быть записано следующим Matlab кодом

dateTimeNow = System.DateTime.Now

Сразу же обратим внимание, что это полный код. От нас не требуется явного подключения каких-либо системных библиотек .Net, и CLR переменная dateTimeNow автоматически становится переменной Matlab'a. Если же данный вызов завершился с ошибкой, можно проверить булевский результат команды, которая проверяет поддержку .Net в среде.

isnetsupported = NET.isNETSupported

В качестве примера вызова метода CLR объекта, прибавим к текущей дате 10 минут, используя привычный дотнетчикам метод AddMinutes

dateTimeNow = dateTimeNow.AddMinutes(10)

В результате запуска данных команд в выводе отображается содержимое полученных объектов


           Date: [1x1 System.DateTime]
            Day: 21
      DayOfWeek: [1x1 System.DayOfWeek]
      DayOfYear: 111
           Hour: 13
           Kind: [1x1 System.DateTimeKind]
    Millisecond: 160
         Minute: 49
          Month: 4
            Now: [1x1 System.DateTime]
         UtcNow: [1x1 System.DateTime]
         Second: 56
          Ticks: 635021489961600559
      TimeOfDay: [1x1 System.TimeSpan]
          Today: [1x1 System.DateTime]
           Year: 2013
       MinValue: [1x1 System.DateTime]
       MaxValue: [1x1 System.DateTime]

Готовим DLL

Прежде чем научиться загружать произвольную сборку в Matlab, займемся ее подготовкой.
В качестве простого примера реализуем в целевой .Net библиотеке c именем Algorithms.dll алгоритм поиска левого верхнего угла ограничивающего прямоугольника бинарного изображения.

Это можно сделать с помощью такого кода на C#:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Algorithms
{
    public class ImageProcessor
    {
        public ImageProcessor() {}

        /// <summary>
        /// Возвращает в массиве coordinates координаты левого верхнего угла бинарной картинки
        /// на изображении. Если их нет - null
        /// </summary>
        /// <param name="bitmap">Входное бинарное изображение</param>
        /// <param name="coordinates">Координаты левого верхнего угла</param>
        public void GetLeftUpperCornerBB(Bitmap bitmap, out int[] coordinates)
        {
            coordinates = null;
            var bitmapData =   bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
                            PixelFormat.Format32bppRgb);

            unsafe
            {
                //получаем указатель на память изображения
                uint* p = (uint*) bitmapData.Scan0.ToPointer();

                //пиксели записаны по строкам
                for (int i = 0; i < bitmap.Height*bitmap.Width; i++)
                {
                    if( (*p & 0xFFFFFF) == 0)  //нашли первый черный пиксель
                    {
                        coordinates  = new int[]  {  i / bitmap.Width , i % bitmap.Width  };
                        break;
                    }
                    p++;
                }
            }

            bitmap.UnlockBits(bitmapData);
           
        }
    }
}

Данный код является специфическим: мы будем рассматривать вызов нестатических public методов из Matlab, которые возвращаются значения с помощью ключевого слова out. Метод GetLeftUpperCornerBB принимает на вход объект класса Bitmap, в котором содержится бинарное изображение, и возвращает в массиве coordinates координаты первого левого верхнего черного пикселя (а если такого на изображении нет, например, в случае пустого изображения, то возвращается null).

Загрузка custom'ных .Net библиотек в Matlab

В директории Matlab проекта создадим новый Matlab-файл Example.m, рядом с которым поместим полученную на предыдущем шаге библиотеку Algorithms.dll (см. скриншот ниже)
Использование .Net библиотек в MATLAB

С помощью вызова функции addAssembly загрузим сборку в Matlab.


 netAssembly = NET.addAssembly('D:WorkMatlabNetIntegrationExampleAlgorithms.dll')

просмотрим список классов загруженной сборки


netAssembly.Classes

результатом будет

ans = 

    'Algorithms.ImageProcessor'

с помощью команды

import Algorithms.*

включаем namespace Algorithms.

Создаем объект класса ImageProcessor и загружаем входное изображение в переменную bitmap

imageProcessor = ImageProcessor();
bitmap = System.Drawing.Bitmap('picture.bmp')

файл picture.bmp при этом располагается в текущей рабочей директории.
Команда

 methods (imageProcessor)

покажет нам список доступных методов данного объекта

Methods for class Algorithms.ImageProcessor:

Equals                delete                le                    
GetHashCode           eq                    lt                    
GetLeftUpperCornerBB  findobj               ne                    
GetType               findprop              notify                
ImageProcessor        ge                    
ToString              gt                    
addlistener           isvalid               

Теперь, запускаем целевой метод GetLeftUpperCornerBB и получаем результат

 coords = imageProcessor.GetLeftUpperCornerBB(bitmap);

Если бы у нас было несколько out параметров (предположим, целых три массива с координатами), то мы бы написали такой код для их получения

 [coords, cords2, cords3] = imageProcessor.GetLeftUpperCornerBB(bitmap);

Отметим, что результат является CLR объектом типа System.Int32[], поэтому для возможного удобства работы с ним существует возможность конвертировать данный массив в native массив Matlab'a. Например:

arrayOfDoubles = coords.double;
arrayOfIntegers = coords.int32;

Обратная конвертация возможна с помощью функции NET.convertArray.

Итого, получаем следующий листинг:


netAssembly = NET.addAssembly('D:WorkMatlabNetIntegrationExampleAlgorithms.dll');
netAssembly.Classes;
import Algorithms.*;

imageProcessor = ImageProcessor();
bitmap = System.Drawing.Bitmap('picture.bmp');
methods (imageProcessor);
coords = imageProcessor.GetLeftUpperCornerBB(bitmap);
arrayOfIntegers = coords.int32;

Заключение

Мы решили задачу создания .Net объекта в Matlab, запуска методов .Net классов и получения результатов.
Отдельно стоит заметить, что согласно документации Matlab выгрузка загруженных .Net модулей не предусмотрена явно. Поэтому, для замены DLL файла потребуется как минимум перезагрузка IDE Matlab. В остальном, в версии 2013a представлена достаточно полная поддержки интеграции .Net в смысле возможностей работы с различными элементами CLR и их атрибутами.

Используемые материалы

Автор: MrEsp

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js