Отображение потока изображений тепловых изображений с плавающей точкой, плавающих [,]

Я работал с камерой FLIR Thermovision последние пару дней и собрал очень простое приложение, в котором есть несколько аспектов, обнаруженных в самых разных местах (большинство из которых здесь, на stackru).

темы

  1. размещение компонента ActiveX в приложении wpf
  2. Float[,] массив для BitmapImage
  3. Отображение связанного растрового изображения в элементе управления изображением wpf с помощью MemoryStream а также BitmapImage

1. Активный X-контроль

Flir Thermovision SDK 2.6 поставляется с компонентом ActiveX DLL. AxCAMCTRLLib.dll. В приложении WinForms вы можете просто добавить инструмент в панель инструментов, щелкнуть и перетащить компонент на форму. Это автоматически добавит правильные ссылки на проект. Чтобы использовать его в приложении wpf, это не сработает. Задним числом это кажется довольно простым, но это не было указано в их документации.

Сначала я должен был вручную перейти к AxCAMCTRLLib.dll и добавить его в список литературы. Затем добавьте новое окно в проект. Это будет скрытое окно, используемое только для размещения компонента ActiveX. Для этого также требуется ссылка WindowsFormsIntegration на компоненты ActiveX шланга.

using CAMCTRLLib;
using AxCAMCTRLLib;

namespace camView
{

public partial class CameraCtrl : Window
{

    public  AxCAMCTRLLib.AxLVCam camera;
    private System.Windows.Forms.Integration.WindowsFormsHost host;

    public CameraCtrl()
    {
        InitializeComponent();

        host = new System.Windows.Forms.Integration.WindowsFormsHost();            
        camera = new AxCAMCTRLLib.AxLVCam();

        host.Child = camera;

        this.grid1.Children.Add(host);

    }

}
}

Теперь в главном окне я могу создать, показать, а затем быстро скрыть новое окно CameraCtrl и иметь доступ к общедоступному элементу управления ActiveX.

public MainWindow()
    {


        InitializeComponent();

        camCtrl = new CameraCtrl();
        camCtrl.BeginInit();

        camCtrl.Show();
        camCtrl.Hide();


        camCtrl.ShowInTaskbar = false;
        camCtrl.ShowActivated = false;


    }

OnClosing метод в MainWindow должен быть изменен, чтобы закрыть скрытое окно.

    protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
    {


        camCtrl.Close();


        base.OnClosing(e);
    }

Теперь я могу получить доступ ко всем методам управления, содержащимся в объекте activex.

2. Переместить массив [,] вBitmapImage

Выходные изображения с камеры могут быть возвращены в различных форматах, но для конкретной камеры, которую я использую, возвращается object который содержит float[,], Поскольку это термический, значения выходного пикселя представляют температуры. Это означает, что они должны быть нормализованы, а затем преобразованы сначала в Bitmap затем хранится в MemoryStream затем добавлен к источнику BitmapImage, Метод, который я использовал, заключается в следующем.

private BitmapImage setDisplayImage(float[,] image)
        {
        float[,] tempStoreImage = new float[240 , 320];
        float max = -10000.0f, min = 10000.0f;
        BitmapImage localBitmap;

        for (int j = 0; j < 320; j++)
        {
            for (int i = 0; i < 240; i++)
            {

                tempStoreImage[i,j] = image[j,i];//have to transpose the image from cam

                if (tempStoreImage[i,j] > max)
                {
                    max = tempStoreImage[i,j];

                }
                if (tempStoreImage[i,j] < min)
                {
                    min = tempStoreImage[i,j];

                }

            }
        }

       if(max != min)//can't divide by zero
        {
            System.Drawing.Bitmap newBitmap = new System.Drawing.Bitmap(320, 240);

            for (int i = 0; i < 240; i++)
            {
                for (int j = 0; j < 320; j++)
                {
                    tempStoreImage[i,j] = (float)Math.Round((double)(tempStoreImage[i,j] - min) * 255 / (max - min));//Normalize and set between 0 - 255
                    System.Drawing.Color newColor = System.Drawing.Color.FromArgb((int)tempStoreImage[i, j],0, 0, 0);//Gray scale color using alpha channel

                    newBitmap.SetPixel(j, i, newColor);
                }
            }

            System.Drawing.Image img = (System.Drawing.Image)newBitmap;


            MemoryStream stream = new MemoryStream();
            img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);//add Bitmap to memory stream
            stream.Position = 0;
            localBitmap = new BitmapImage();
            localBitmap.BeginInit();  

            localBitmap.StreamSource = stream;  //
            localBitmap.EndInit();
        }
        else localBitmap = new BitmapImage();//dark image


        return localBitmap;

    }

3. Отображение изображения

Я создал простой вспомогательный класс:

   class BindData  : INotifyPropertyChanged
    {

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string PropertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
    }

    BitmapImage _image;




    public BitmapImage Image
    {
        get { return _image; }

        set
        {
            _image = value;
            _image.Freeze();
            OnPropertyChanged("Image");

        }


    }



}

А затем создал статический вспомогательный объект класса в MainWindow (вероятно, не обязательно должен быть статическим, но я планирую использовать его в других классах.) BindData bind = new BindData() и установить image1.DataContext = bind, Затем установите привязку и размер окна в соответствии с моим массивом:

<Image Height="240" HorizontalAlignment="Left" Margin="204,21,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="320" Source="{Binding Image}"/>

И, наконец, снятые изображения с помощью System.Timers.Timer:

private void cameraCap()
    {
        if (continueDisplay)
        {
            captureTimer.Stop();
            lock (camCtrl)
            {
              object yo = camCtrl.camera.GetImage(3);
              bind.Image = setDisplayImage(yo as float[,]);


            }
            captureTimer.Start();
        }
        else
            captureTimer.Stop();
    }


private void capture_Click(object sender, RoutedEventArgs e)
    {


        continueDisplay = true;


        captureTimer.Start();


    }

private void kill_Click (отправитель объекта, RoutedEventArgs e) { continueDisplay = false; }

Несколько вещей, с которыми я столкнулся при использовании таймера. Во-первых, время приложения и время камеры не совпадают, поэтому я останавливаю таймер в начале захвата и запускаю его снова после окончания. К счастью, поток ожидает, пока камера вернет изображение. Это заботится о отставании по большей части. Второй _image.Freeze() утверждение важно. Без этого вы получите "Необходимо создать DependencySource в том же потоке, что и DependencyObject". ошибка однажды инициирована. Метод Freeze делает изображение доступным для других потоков.

1 ответ

Решение

Это относится к codereview.stackexchange.com

Другие вопросы по тегам