using Bro.Common.Factory; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model.Interface; using HalconDotNet; using Newtonsoft.Json; //using MvCamCtrl.NET; using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Drawing; using System.Drawing.Design; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.Design; using static Bro.Common.Helper.EnumHelper; namespace Bro.Common.Base { public delegate void OnUpdateCameraImageDelegate(CameraBase camera, Bitmap image, string imagePath); public abstract class CameraBase : DeviceBase { #region DeviceBase protected override void Start() { if (clearImageTimer == null) { clearImageTimer = new System.Threading.Timer((o) => { ClearImage(); }, null, 0, 1000 * 60 * 120); } } protected override void Stop() { if (clearImageTimer != null) { clearImageTimer.Change(-1, -1); clearImageTimer.Dispose(); clearImageTimer = null; } } #endregion //public Action OnLog; /// /// 运行模式 扫描or拍照 /// public EnumHelper.CameraOpMode OpMode { get; set; } = EnumHelper.CameraOpMode.Snapshot; /// /// 扫描到的图片 /// public virtual object ImageObj { get; set; } = null; public AutoResetEvent ImageGetHandle = new AutoResetEvent(false); public AutoResetEvent ImageSaveDoneHandle = new AutoResetEvent(false); private Bitmap showImage; /// /// 输出显示的图片 /// public virtual Bitmap ShowImage { get { return showImage; } set { try { showImage = value; if (showImage != null) { UpdateShowImage?.Invoke(this, new Bitmap(showImage), null); } if (OpMode == EnumHelper.CameraOpMode.Snapshot) { ImageGetHandle.Set(); } } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, $"相机异常信息:{ex.GetExceptionMessage()}"); } } } #region 使用指针操作图像的必须信息 ///// ///// 图片内容的指针 ///// //public IntPtr ImagePtr { get; set; } = IntPtr.Zero; //public int ImagePtrSize { get; set; } = 0; //public int? ImageWidth //{ // get // { // return ShowImage?.Width; // } //} //public int? ImageHeight //{ // get // { // return ShowImage?.Height; // } //} #endregion private string imageFilePath; /// /// 扫描图片保存文件路径 /// public string ImageFilePath { get { return imageFilePath; } set { if (imageFilePath != value) { imageFilePath = value; } } } /// /// 一次性抓拍 /// /// public abstract void Snapshot(); public abstract void Snapshot(out HObject hImage); public abstract void Snapshot(IOperationConfig config, out HObject hImage); /// /// 开始扫描 /// /// public abstract void StartScan(); /// /// 结束扫描 /// public abstract void StopScan(); /// /// 释放图片数据 /// protected virtual void FreeImage() { if (ShowImage != null) { ShowImage.Dispose(); } } /// /// 从设备硬件信息获取设备设置参数 /// /// public abstract IDeviceConfig GetDeviceConfigFromDevice(); public abstract IOperationConfig GetOperationConfigFromDevice(); public abstract void UploadOperationConfig(IOperationConfig config); public event OnUpdateCameraImageDelegate UpdateShowImage; public abstract HalconRelatedCameraInitialConfigBase IConfig { get; } protected virtual async void SaveImage(Bitmap map, HalconRelatedCameraOprerationConfigBase opConfig = null) { await Task.Run(() => { if ((opConfig?.IsSaveImage) ?? false) { string subDir = (opConfig ?? new HalconRelatedCameraOprerationConfigBase()).ImageSaveSubDirectory; if (string.IsNullOrWhiteSpace(subDir)) { subDir = DateTime.Now.ToString("yyyyMMdd"); } else { subDir = Path.Combine(DateTime.Now.ToString("yyyyMMdd"), subDir); } string imgDir = Path.Combine(IConfig.ImgDirectory, subDir); DirectoryInfo dir = new DirectoryInfo(imgDir); if (!dir.Exists) { dir.Create(); } try { //if ((opConfig?.IsSaveImage) ?? false) { //ImageSaveDoneHandle.Reset(); string fileName = DateTime.Now.ToString("HHmmssfff"); if (opConfig.ImageType == ImageType.Bmp) { ImageFilePath = Path.Combine(imgDir, $"{fileName}.bmp"); map.Save(ImageFilePath, ImageFormat.Bmp); } else { ImageFilePath = Path.Combine(imgDir, $"{fileName}.jpg"); map.Save(ImageFilePath, ImageFormat.Jpeg); } ImageSaveDoneHandle.Set(); } } catch (Exception ex) { } } }); } #region 定时清理图片 static object _clearImageLock = new object(); protected void ClearImage() { if (IConfig.SaveImageDayLimit > 0) { lock (_clearImageLock) { OnLog?.Invoke(DateTime.Now, this, $"ClearImage Start。 {this.IConfig.CameraIP}"); try { DirectoryInfo dirImage = new DirectoryInfo(IConfig.ImgDirectory); if (dirImage.Exists) { DateTime dtNow = DateTime.Now; var folderList = dirImage.GetDirectories().ToList(); folderList = folderList.Where(f => { if (f.Name.Length < 8) return false; DateTime dt = DateTime.Now; string name = f.Name.Substring(0, 4) + "/" + f.Name.Substring(4, 2) + "/" + f.Name.Substring(6); return DateTime.TryParse(name, out dt); }).OrderBy(u => u.Name).ToList(); if (folderList.Count > IConfig.SaveImageDayLimit) { folderList.Take(folderList.Count - IConfig.SaveImageDayLimit).ToList().ForEach(f => { f.Delete(true); }); } } } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, $"ClearImage Exception\r\n{ex.GetExceptionMessage()}"); } OnLog?.Invoke(DateTime.Now, this, $"ClearImage Done\r\n {this.IConfig.CameraIP}"); } } } private System.Threading.Timer clearImageTimer = null; #endregion } public class CameraOperationConfigBase : OperationConfigBase, IComparer, IComparable { /// /// 运行模式 /// public EnumHelper.CameraOpMode OpMode { get; set; } = EnumHelper.CameraOpMode.Snapshot; #region 运行参数 /// /// 该参数表示哪些值参与设置 /// public string ConfigItems { get; set; } = "[]"; //= "['BalanceRed','BalanceGreen','BalanceBlue','Exposure','Saturation','Gain','WhiteBalance']"; [CameraPara("红平衡", "BalanceRed", 2, 1, 1000)] public double BalanceRed { get; set; } = 1; [CameraPara("绿平衡", "BalanceGreen", 2, 1, 1000)] public double BalanceGreen { get; set; } = 1; [CameraPara("蓝平衡", "BalanceBlue", 2, 1, 1000)] public double BalanceBlue { get; set; } = 1; [CameraPara("白平衡", "WhiteBalance", 2, 0, 1000)] public double WhiteBalance { get; set; } = 1; [CameraPara("曝光时间", "Exposure", 60000, 1, 1)] public double Exposure { get; set; } = 10; [CameraPara("饱和度", "Saturation", 2, 1, 1000)] public double Saturation { get; set; } = 1; [CameraPara("增益补偿", "Gain", 200, 0, 1)] public double Gain { get; set; } = 1; [CameraPara("采像宽度", "Width", 10000, 0, 1)] public int Width { get; set; } = 0; [CameraPara("采像高度", "Height", 10000, 0, 1)] public int Height { get; set; } = 0; [ConfigOutputResource("OutputResultCommon")] public override int ResultOutput { get; set; } public int Compare(CameraOperationConfigBase x, CameraOperationConfigBase y) { //List yItems = JsonConvert.DeserializeObject>(y.ConfigItems); string yItems = y.ConfigItems.Trim(new char[] { '[', ']' }); if (string.IsNullOrWhiteSpace(yItems)) { return 0; } else { if (yItems.Contains("BalanceBlue")) { if (x.BalanceBlue != y.BalanceBlue) { return 1; } } if (yItems.Contains("BalanceGreen")) { if (x.BalanceGreen != y.BalanceGreen) { return 1; } } if (yItems.Contains("BalanceRed")) { if (x.BalanceRed != y.BalanceRed) { return 1; } } if (yItems.Contains("WhiteBalance")) { if (x.WhiteBalance != y.WhiteBalance) { return 1; } } if (yItems.Contains("Exposure")) { if (x.Exposure != y.Exposure) { return 1; } } if (yItems.Contains("Saturation")) { if (x.Saturation != y.Saturation) { return 1; } } if (yItems.Contains("Gain")) { if (x.Gain != y.Gain) { return 1; } } if (yItems.Contains("Width")) { if (x.Width != y.Width) { return 1; } } if (yItems.Contains("Height")) { if (x.Height != y.Height) { return 1; } } return 0; } } /// /// y作为原始数据 当前数据如果ConfigItem为空时,默认无变化 /// /// 原始数据 /// public int CompareTo(CameraOperationConfigBase y) { string xItems = ConfigItems.Trim(new char[] { '[', ']' }); if (string.IsNullOrWhiteSpace(xItems)) { return 0; } else { if (xItems.Contains("BalanceBlue")) { if (BalanceBlue != y.BalanceBlue) { return 1; } } if (xItems.Contains("BalanceGreen")) { if (BalanceGreen != y.BalanceGreen) { return 1; } } if (xItems.Contains("BalanceRed")) { if (BalanceRed != y.BalanceRed) { return 1; } } if (xItems.Contains("WhiteBalance")) { if (WhiteBalance != y.WhiteBalance) { return 1; } } if (xItems.Contains("Exposure")) { if (Exposure != y.Exposure) { return 1; } } if (xItems.Contains("Saturation")) { if (Saturation != y.Saturation) { return 1; } } if (xItems.Contains("Gain")) { if (Gain != y.Gain) { return 1; } } if (xItems.Contains("Width")) { if (Width != y.Width) { return 1; } } if (xItems.Contains("Height")) { if (Height != y.Height) { return 1; } } return 0; } } public override bool Equals(object obj) { CameraOperationConfigBase cocb = obj as CameraOperationConfigBase; if (cocb == null) { return false; } return CompareTo(cocb) == 0; } #endregion } public class CameraDeviceConfigBase : DeviceConfigBase { [DefaultValue("['MaxNumBuffer','GammaValue','ReverseX','ReverseY']")] public string ConfigItems { get; set; } = "['MaxNumBuffer','GammaValue','ReverseX','ReverseY']"; public long MaxNumBuffer { get; set; } public double GammaValue { get; set; } = double.MinValue; public bool ReverseX { get; set; } public bool ReverseY { get; set; } } public class CameraInitialConfigBase : InitialConfigBase { /// /// 该参数表示哪些参数值对本相机有效 /// public string EnableItems { get; set; } } public class CameraInputConfigBase : InputConfigBase { } #region HalconRelatedCameara public class HalconRelatedCameraOprerationConfigBase : OperationConfigBase, INotifyPropertyChanged, IComplexDisplay, IHalconToolPath { private float exposure = 0; /// /// 曝光 /// [Category("取像配置")] [Description("曝光")] public float Exposure { get => exposure; set { if (exposure != value) { exposure = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Exposure")); } } } /// /// 增益 /// [Category("取像配置")] [Description("增益")] public float Gain { get; set; } [Category("取像配置")] [Description("曝光修改后等待时间,单位ms。针对部分场景确保曝光修改及时生效。")] public int ExposureWaitTime { get; set; } [Category("取像配置")] [Description("拍摄后曝光值。可在一次拍摄后将曝光修改为下次拍摄的曝光值,节约曝光生效时间。")] public float ExposureAfterSnap { get; set; } [Browsable(false)] public override int ResultOutput { get; set; } [Category("算法配置")] [Description("算法路径")] [Editor(typeof(FileDialogEditor), typeof(UITypeEditor))] public string AlgorithemPath { get; set; } [Category("延时配置")] [Description("拍照前延时")] public int DelayBefore { get; set; } = 0; [Category("延时配置")] [Description("拍照后延时")] public int DelayAfter { get; set; } = 0; [Category("图片保存")] [Description("图片保存文件夹分路径")] public string ImageSaveSubDirectory { get; set; } [Category("图片保存")] [Description("是否保存图片")] public bool IsSaveImage { get; set; } = true; [Category("图片保存")] [Description("图片保存格式")] public ImageType ImageType { get; set; } = ImageType.Jpeg; [Category("图片保存")] [Description("是否保存拟合/结果图片")] public bool IsSaveFitImage { get; set; } = false; [Category("图片保存")] [Description("是否保存NG图片")] public bool IsSaveNGImage { get; set; } = false; [Category("图片保存")] [Description("拟合/结果图片保存路径")] [Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))] public string FitImagePath { get; set; } public event PropertyChangedEventHandler PropertyChanged; public string GetDisplayText() { return $"{(IsEnabled ? "" : "停用 ")}曝光:{Exposure.ToString("f2")}"; } public List GetHalconToolPathList() { return new List() { AlgorithemPath }; } } public class HalconRelatedCameraInitialConfigBase : InitialConfigBase { [Category("相机设置")] [Description("驱动类型")] [TypeConverter(typeof(CameraTypeConverter))] public new string DriverType { get; set; } = "HikCamera"; [Category("相机设置")] [Description("相机序列号")] [TypeConverter(typeof(HalconSerialNumConverter))] public virtual string SerialNum { get; set; } [Category("相机设置")] [Description("相机IP地址")] public string CameraIP { get; set; } [Category("相机设置")] [Description("上位机IP地址")] public string ComputerIP { get; set; } [Category("相机设置")] [Description("视频模式扫描间隔 单位毫秒")] public int ScanInterval { get; set; } = 100; [Category("保存设置")] [Description("采图保存目录")] [Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))] public string ImgDirectory { get; set; } = @"../Images"; [Category("保存设置")] [Description("图片保存天数")] [Browsable(false)] public int SaveImageDayLimit { get; set; } = 0; [Category("拍摄设置")] [Description("默认曝光值。相机开启后就设置该曝光值。")] public float DefaultExposure { get; set; } } public class HalconSerialNumConverter : ComboBoxItemTypeConvert { public override void GetConvertHash() { HTuple deviceList = null; AutoResetEvent handle = new AutoResetEvent(false); Task.Run(() => { HOperatorSet.InfoFramegrabber("GigEVision", "info_boards", out HTuple deviceInfo, out deviceList); handle.Set(); }); handle.WaitOne(5000); if (deviceList != null) { for (int i = 0; i < deviceList.Length; i++) { var list = deviceList[i].S.Split(new char[] { ':', '|' }, StringSplitOptions.RemoveEmptyEntries); _hash[list[1].Trim()] = list[3].Trim() + "--" + list[1].Trim(); } } } } #endregion public class CameraTypeConverter : StringConverter { public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { return true; } public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) { return true; } public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { List devices = DeviceFactory.GetAllSupportDeviceTypeNames(); devices = devices.Where(u => u.EndsWith("Camera")).ToList(); return new StandardValuesCollection(devices); } } public class CameraInitialConfigEditor : UITypeEditor { public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context) { return UITypeEditorEditStyle.Modal; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null) { Form form = new Form(); form.FormBorderStyle = FormBorderStyle.SizableToolWindow; form.StartPosition = FormStartPosition.CenterParent; form.Text = context.PropertyDescriptor.DisplayName + "--" + context.PropertyDescriptor.Description; PropertyGrid pg = new PropertyGrid(); pg.Dock = DockStyle.Fill; pg.ToolbarVisible = false; string driverType = (value as HalconRelatedCameraInitialConfigBase).DriverType; if (!string.IsNullOrWhiteSpace(driverType)) { IInitialConfig initial = ConfigFactory.GetInitialConfig(driverType); initial.DataFrom(value); value = initial; } pg.SelectedObject = value; form.Controls.Add(pg); form.ShowDialog(); value = pg.SelectedObject; return value; } return base.EditValue(context, provider, value); } } public static class CameraHelper { public static CameraBase GetCameraInstance(string driverType) { return DeviceFactory.GetDeviceInstanceByTypeName(driverType) as CameraBase; } } }