显示来自FLIR相机的`float [,]`热图像的图像输入

时间:2013-11-19 18:57:46

标签: c# wpf activex bitmapimage flir

过去几天我一直在使用FLIR Thermovision相机,并将一个非常简单的应用程序整合在一起,该应用程序在许多不同的地方都有一些方面(其中大部分都在stackoverflow上)。

主题

  1. 在wpf应用程序中托管ActiveX组件
  2. Float[,]数组到BitmapImage
  3. 使用MemoryStreamBitmapImage
  4. 在wpf图像控件中显示绑定位图

    1。 Active 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;
    
    
        }
    
    必须修改OnClosing中的

    MainWindow方法以关闭隐藏窗口。

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
    
    
            camCtrl.Close();
    
    
            base.OnClosing(e);
        }
    

    有了这个,我现在可以访问activex对象中包含的所有控制方法。

    2。将[,]数组浮动到BitmapImage

    来自相机的输出图像可以以多种不同的格式返回,但对于我正在使用的特定相机,它会返回包含object的{​​{1}}。由于它是热的,输出像素值代表温度。这意味着必须将它们标准化,然后先转换为float[,],然后存储在Bitmap中,然后添加到MemoryStream的来源。我使用的方法如下。

    BitmapImage

    3。显示图像

    我创建了一个简单的帮助类:

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

    然后在MainWindow中创建了一个静态助手类对象(可能不需要是静态的,但我打算在其他类中使用它。) 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"); } } } 并设置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 kill_Click(object sender,RoutedEventArgs e)         {             continueDisplay = false;         }

    我使用计时器遇到了一些事情。首先,应用程序时间和摄像机时间不一样,所以我在捕获开始时停止计时器并在结束后重新启动计时器。幸运的是,线程等待相机返回图像。这在很大程度上解决了滞后问题。其次,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(); } 声明至关重要。没有它,您将获得“必须在与DependencyObject相同的线程上创建DependencySource”。错误一旦启动。 Freeze方法使图像可供其他线程使用。

1 个答案:

答案 0 :(得分:0)

这确实属于codereview.stackexchange.com