Avalonia操作海康相机

1.MVS中确保相机正常

前端代码

复制代码
					<Grid RowDefinitions="50,40,30,*">
						<ComboBox ItemsSource="{Binding CameraList}"
								  SelectedItem="{Binding SelectedCamera}"
								  PlaceholderText="请选择一个相机" />
						<StackPanel Grid.Row="1" Orientation="Horizontal">
							<TextBox Text="{Binding CameraIP}" Foreground="White" ></TextBox>
							<Button    Click="OpenCamera" Width="80"  HorizontalAlignment="Stretch" Content="OpenCamera" Classes.active="{Binding VisionPageIsActive}"> 
							<Button   Click="CloseCamera" Width="80"   HorizontalAlignment="Stretch" Content="关闭相机" Foreground="White"></Button>
							<Button  Click="GetCameraFrame" Width="80"   HorizontalAlignment="Stretch" Content="获取当前帧" Foreground="White" Background="Green"></Button>
 
							<TextBox Text="{Binding ProgramLog}" Foreground="White" ></TextBox>
						</StackPanel>
						<Grid Grid.Row="3" Background="LightSkyBlue">
							<Image    x:Name="MyImage" Source="{Binding DisplayImage}" Stretch="UniformToFill"   />
 
						</Grid> 
					</Grid> 

代码段

复制代码
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media.Imaging; 
using LinkAsiaVisionV2.ViewModels;
using MvCameraControl;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;

namespace LinkAsiaVisionV2.Views
{
    public partial class MainView : Window
    {
        // ch:枚举的相机类型 | en:TLayerType for enumerate devices
        readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice
    | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice;

        List<IDeviceInfo> deviceInfoList = new List<IDeviceInfo>();
        IDevice device = null;

        bool isGrabbing = true;        // ch:是否正在取图 | en: Grabbing flag
        Thread receiveThread = null;    // ch:接收图像线程 | en: Receive image thread
        IntPtr pictureBoxHandle = IntPtr.Zero; // ch:显示图像的控件句柄 | en: Control handle for image display

        public MainView()
        {
            InitializeComponent();
        }

        // 重写 OnLoaded 方法
        protected override void OnLoaded(RoutedEventArgs e)
        {
            base.OnLoaded(e); // 调用基类方法,确保事件链正常传递
                              // 在这里编写你的初始化逻辑
            Console.WriteLine("窗口已完全加载!");
            // 例如:加载数据、启动动画、或初始化第三方组件
            // ch: 初始化 SDK | en: Initialize SDK
            SDKSystem.Initialize();

            // ch: 枚举设备 | en: Enum Device List
            RefreshDeviceList();
        }


        private void OnTitleBarPointerPressed(object? sender, PointerPressedEventArgs e)
        {
            if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
                this.BeginMoveDrag(e);
        }

        private void RefreshDeviceList()
        {
            if (DataContext is MainViewModel vm)
            {
                vm.CameraList.Clear();

                // ch:创建设备列表 | en:Create Device List
          
                int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out deviceInfoList);
                if (nRet != MvError.MV_OK)
                {
                    // ShowErrorMsg("Enumerate devices fail!", nRet);
                    return;
                }

                // ch:在窗体列表中显示设备名 | en:Display device name in the form list
                for (int i = 0; i < deviceInfoList.Count; i++)
                {
                    IDeviceInfo deviceInfo = deviceInfoList[i]; 
                    IGigEDeviceInfo gigEDevice = (IGigEDeviceInfo)deviceInfo;
         
                    uint nIp1 = ((gigEDevice.CurrentIp & 0xff000000) >> 24);
                    uint nIp2 = ((gigEDevice.CurrentIp & 0x00ff0000) >> 16);
                    uint nIp3 = ((gigEDevice.CurrentIp & 0x0000ff00) >> 8);
                    uint nIp4 = (gigEDevice.CurrentIp & 0x000000ff);
                    Console.WriteLine("DevIP: {0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4);
                  
                    if (deviceInfo.UserDefinedName != "")
                    { 
                        vm.CameraList.Add(deviceInfo.TLayerType.ToString() + ": " + deviceInfo.UserDefinedName + " (" + deviceInfo.SerialNumber + ")");
                    }
                    else
                    {
                        vm.CameraList.Add(deviceInfo.TLayerType.ToString() + ": " + deviceInfo.ManufacturerName + $" IP: [{nIp1}.{nIp2}.{nIp3}.{nIp4}]  " + deviceInfo.ModelName + " (" + deviceInfo.SerialNumber + ")");
                    }
                }
 
            }

        }

        private void OpenCamera(object? sender, RoutedEventArgs e)
        {
            int ret = 0;
            if (DataContext is MainViewModel vm)
            {
                int index = vm.CameraList.FindIndex(s => s.Contains(vm.CameraIP));
                // vm.CameraList.ind(vm.CameraIP);

                IDeviceInfo deviceInfo = deviceInfoList[index];
                /*创建相机实例*/
                device = DeviceFactory.CreateDevice(deviceInfo);

                /*打开相机*/
                ret = device.Open();

                vm.ProgramLog = $"相机打开 ret = {ret}";
                //MessageBox.Show(errorMsg, "PROMPT");
                /*如果是网口相机*/
                if (device is IGigEDevice)
                {
                    IGigEDevice gigEDevice = device as IGigEDevice;

                    /*配置网口相机的最佳包大小*/
                    int packetSize;
                    gigEDevice.GetOptimalPacketSize(out packetSize);
                    gigEDevice.Parameters.SetIntValue("GevSCPSPacketSize", packetSize);
                }
                else if (device is IUSBDevice)
                {
                    /*设置USB同步读写超时时间*/
                    IUSBDevice usbDevice = device as IUSBDevice;
                    usbDevice.SetSyncTimeOut(1000);
                }

                // ch:设置采集连续模式 | en:Set Continues Acquisition Mode
                device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
                device.Parameters.SetEnumValueByString("TriggerMode", "Off");


                //receiveThread = new Thread(ReceiveThreadProcess);
                //receiveThread.Start();



                // ch:开启抓图线程 | en: Start the grabbing thread
                //Thread GrabThread = new Thread(FrameGrabThread);
                //GrabThread.Start(device.StreamGrabber);
                //GrabThread.Abort();
                // ch:开启抓图 | en: start grab image
                ret = device.StreamGrabber.StartGrabbing();
                if (ret != MvError.MV_OK)
                {
                    isGrabbing = false;
                    // receiveThread.Join();
                    Console.WriteLine("Start grabbing failed:{0:x8}", ret);
                    return;
                }

                vm.ProgramLog = $"开始采集 ret = {ret}";
            }
        }

        private void CloseCamera(object? sender, RoutedEventArgs e)
        {
            int ret = 0;
            if (DataContext is MainViewModel vm)
            { 

                ret = device.StreamGrabber.StopGrabbing();
                /*关闭相机*/
                ret = device.Close();
                if (ret != MvError.MV_OK)
                {
                    Console.WriteLine("Close device fail: {0}", ret);
                }
                else
                {
                    Console.WriteLine("Close device success!");
                }

                // ch:销毁设备 | en:Destroy device
                device.Dispose();
                device = null; 
  
                vm.ProgramLog = $"相机关闭 ret = {ret}"; 
            }
        }

        private void GetCameraFrame(object? sender, RoutedEventArgs e)
        {
            if (DataContext is MainViewModel vm)
            {
                // while (isGrabbing)
                {
                    IFrameOut frameOut;

                    int nRet = device.StreamGrabber.GetImageBuffer(1000, out frameOut);
                    if (MvError.MV_OK == nRet)
                    {

                        IImage inputImage = frameOut.Image;

                        OpenCvSharp.Mat mat = ByteToMatColor(inputImage.PixelData, ((int)inputImage.Width), ((int)inputImage.Height));
                        vm.CameraBitmap = ToAvaloniaBitmap(mat);
                        vm.DisplayImage = ToAvaloniaBitmap(mat); 
                        vm.ProgramLog = $"获取当前帧 Width = {frameOut.Image.Width} {DateTime.Now}"; 
                    }
                    else
                    {
                        vm.ProgramLog = $"获取当前帧失败  {nRet} {DateTime.Now}";
                    } 
                    device.StreamGrabber.FreeImageBuffer(frameOut);
                } 
            } 
        } 

        public OpenCvSharp.Mat ByteToMatColor(byte[] data, int width, int height)
        {
            OpenCvSharp.Mat src = new OpenCvSharp.Mat(height, width, OpenCvSharp.MatType.CV_8UC3);
            int length = height * width * 3; // or src.Height * src.Step;
            Marshal.Copy(data, 0, src.Data, length);
            return src;
        }

        public Bitmap ToAvaloniaBitmap( OpenCvSharp.Mat mat)
        {
            if (mat == null || mat.Empty())
                throw new ArgumentNullException(nameof(mat));

            OpenCvSharp.Mat matRgb = new OpenCvSharp.Mat();

            // OpenCV 默认为 BGR 格式,必须转成 RGB
            if (mat.Channels() == 3)
            {
                OpenCvSharp.Cv2.CvtColor(mat, matRgb, OpenCvSharp.ColorConversionCodes.BGR2RGB);
            }
            // 灰度图
            else if (mat.Channels() == 1)
            {
                OpenCvSharp.Cv2.CvtColor(mat, matRgb, OpenCvSharp.ColorConversionCodes.GRAY2BGR);
                OpenCvSharp.Cv2.CvtColor(matRgb, matRgb, OpenCvSharp.ColorConversionCodes.BGR2RGB);
            }
            else
            {
                matRgb = mat.Clone();
            }

            try
            {
                // 内存流编码为 JPG/PNG
                using var ms = new System.IO.MemoryStream();
                matRgb.WriteToStream(ms);

                // 关键:Avalonia 从流创建 Bitmap
                ms.Position = 0;
                return new Bitmap(ms);
            }
            finally
            {
                matRgb.Dispose(); // 必须释放,防止内存泄漏
            }
        }

    }
}

ViewModel代码

复制代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using LinkAsiaVisionV2.Factories;
using LinkAsiaVisionV2.Message;
using LinkAsiaVisionV2.Views;
using Microsoft.Extensions.DependencyInjection;
using MvCameraControl;
using System;
using System.Collections.Generic;
 
using Tmds.DBus.Protocol;

namespace LinkAsiaVisionV2.ViewModels
{
    public partial class MainViewModel : ViewModelBase
    {
        private PageFactory _pageFactory;
 
        [ObservableProperty]
        public partial List<string> CameraList { get; set; } = new List<string>();

        [ObservableProperty]
        public partial string SelectedCamera { get; set; }

        [ObservableProperty]
        public partial string ProgramLog { get; set; }

        [ObservableProperty]
        public partial Bitmap CameraBitmap { get; set; }

        [ObservableProperty]
        private Bitmap? _displayImage;



        [ObservableProperty]
        public partial string CameraIP { get; set; } = "192.168.0.11";

        [ObservableProperty] 
        [NotifyPropertyChangedFor(nameof(VisionPageIsActive))]
        private PageViewModel _currentPage;

  
        public MainViewModel(PageFactory pageFactory)
        {
            WeakReferenceMessenger.Default.Register<OrderMessage>(this, (recipient, message) =>
            {
                // 当收到 MyMessage 时,这个 Lambda 表达式会被执行
                //message.Key
                var receivedValue = message.Value;
                //IsVisibleVisionArea = true;
                // 处理消息...
            });

            _pageFactory = pageFactory;
            GotoHome();
        }

        [RelayCommand]
        public void GotoHome()
        {
            CurrentPage = _pageFactory.GetPageViewModel(Data.ApplicationPageNames.Home);
  
        } 
    }
}

需要注意的是bitmap必须是Avalonia的,不能是system.drawing的,因为这个问题耽误了一天才弄出来

相关推荐
RoboWizard1 天前
移动固态硬盘摔了一下后无法识别,数据还能恢复吗?
大数据·人工智能·数码相机·智能手机·性能优化·无人机
bubiyoushang8881 天前
Qt中调用相机进行拍照并实现图像处理
图像处理·数码相机·qt
nashane2 天前
HarmonyOS 6.0 分布式相机实战:调用远端设备摄像头与AI场景识别(API 11+)
分布式·数码相机·harmonyos·harmonyos 5
光电的一只菜鸡2 天前
相机光学(五十一)——前置附加工具透镜
数码相机
中达瑞和-高光谱·多光谱2 天前
从陶罐暗纹到油画修改:一台便携式高光谱相机如何“复活”文物?
数码相机
中达瑞和-高光谱·多光谱2 天前
新品发布 | 稳定可靠,小而不凡!VIX-N221推扫式高光谱相机以高性价比赋能多样应用
数码相机
qq_526099132 天前
图像采集卡:藏在机器“眼睛”背后的枢纽,撑起视觉智能化半边天
数码相机·opencv·计算机视觉
jqrbcts2 天前
关于汇川四轴机器人单双数平移
数码相机·机器人
吴梓穆2 天前
UE5 移动鼠标玩家不动,相机围绕玩家移动
数码相机·ue5