簡體   English   中英

顯示來自FLIR攝像機的“ float [,]”熱圖像的圖像供稿

[英]Display image feed of `float[,]` thermal images from FLIR camera

最近幾天,我一直在使用FLIR Thermovision攝像機進行工作,並收集了一個非常簡單的應用程序,該應用程序在許多不同的地方都有很多方面(其中大多數都在stackoverflow上)。

主題

  1. 在wpf應用程序中托管ActiveX組件
  2. Float[,]數組到BitmapImage
  3. 通過使用MemoryStreamBitmapImage在wpf圖像控件中顯示綁定的位圖

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);

    }

}
}

現在,我可以在MainWindow中創建,顯示然后立即隱藏一個新窗口CameraCtrl並可以訪問公共ActiveX控件。

public MainWindow()
    {


        InitializeComponent();

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

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


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


    }

還必須修改MainWindow OnClosing方法以關閉隱藏的窗口。

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


        camCtrl.Close();


        base.OnClosing(e);
    }

這樣,我現在可以訪問activex對象中包含的所有控制方法。

2. Float [,]數組到BitmapImage

相機的輸出圖像可以多種格式返回,但是對於我正在使用的特定相機,它返回一個包含float[,]object 由於是熱的,因此輸出像素值表示溫度。 這意味着必須對其進行規范化,然后首先將其轉換為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();


    }

私有無效kill_Click(object sender,RoutedEventArgs e){continueDisplay = false; }

我使用計時器遇到了一些麻煩。 首先,應用程序時序和相機時序不同,因此,我在捕獲開始時停止計時器,並在結束后重新啟動它。 幸運的是,線程等待相機返回圖像。 這樣可以最大程度地避免延遲。 其次, _image.Freeze()語句至關重要。 沒有它,您將得到“必須在與DependencyObject相同的線程上創建DependencySource”。 錯誤一旦啟動。 Freeze方法使圖像可用於其他線程。

這確實屬於codereview.stackexchange.com

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM