Pull to refresh

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

Reading time5 min
Views5.8K
Привет Хабровчанам! На Хабре уже обсуждался вопрос интеграции .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 координаты левого верхнего угла бинарной картинки
        /// на изображении. Если их нет - {-1,-1}
        /// </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();
                 coordinates  = new int[2]{-1,-1}; 
                //пиксели записаны по строкам
                for (int i = 0; i < bitmap.Height*bitmap.Width; i++)
                {
                    if( (*p & 0xFFFFFF) == 0)  //нашли первый черный пиксель
                    {
                        coordinates[0]  =   i / bitmap.Width;
                        break;
                    }
                    p++;
                }
                p = (uint*) bitmapData.Scan0.ToPointer();
                for (int i = 0; i < bitmap.Height*bitmap.Width; i++)
                {
                    if( (p[( i % bitmap.Height) * bitmap.Width  + ( i / bitmap.Height)  ] & 0xFFFFFF) == 0)  //нашли первый черный пиксель
                    {
                        coordinates[1]  =   i / bitmap.Height;
                        break;
                    }
                }
                
            }

            bitmap.UnlockBits(bitmapData);
           
        }
    }
}



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

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



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


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

 netAssembly = NET.addAssembly('D:\Work\MatlabNetIntegrationExample\Algorithms.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:\Work\MatlabNetIntegrationExample\Algorithms.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 и их атрибутами.

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


Tags:
Hubs:
+19
Comments7

Articles

Change theme settings