| | |
| | | using System.Drawing.Imaging; |
| | | using System.IO; |
| | | using System.Linq; |
| | | using System.Runtime.InteropServices; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | using static Bro.Common.Helper.EnumHelper; |
| | |
| | | #endregion |
| | | |
| | | #region 图片相关 |
| | | public event Action<CameraBase, Bitmap, string> OnImageUpdated; |
| | | public Action<CameraBase, Bitmap, string> OnImageUpdated; |
| | | |
| | | public Action<CameraBase, HObject, string> OnHImageOutput { get; set; } |
| | | public event Action OnCameraOpModeChanged; |
| | |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public abstract void Snapshot(); |
| | | public abstract IImageSet Snapshot(IOperationConfig config); |
| | | |
| | | public virtual ImageSet Snapshot(IOperationConfig config) |
| | | public virtual void InitialImageSet(IImageSet set, ImageSaveOption saveOption) |
| | | { |
| | | OpMode = CameraOpMode.SingleSnapShot; |
| | | |
| | | ImageSet set = new ImageSet(); |
| | | CameraOprerationConfigBase opConfig = config as CameraOprerationConfigBase; |
| | | set.ImageSaveOption.DataFrom(opConfig.ImageSaveOption); |
| | | //CameraOprerationConfigBase opConfig = config as CameraOprerationConfigBase; |
| | | set.ImageSaveOption.DataFrom(saveOption); |
| | | |
| | | set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage; |
| | | set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage; |
| | | set.IsAddtionalSaved = !string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType); |
| | | set.OnImageSetTimeout += ImageSet_OnImageSetTimeout; |
| | | _imageSetList.Add(set); |
| | | set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType); |
| | | //set.OnImageSetTimeout += ImageSet_OnImageSetTimeout; |
| | | |
| | | return set; |
| | | _imageSetList[set.Id] = set; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | #endregion |
| | | |
| | | #region 基元处理 |
| | | public event Action<CameraBase, List<IShapeElement>, string> OnElementsUpdated; |
| | | public Action<CameraBase, List<IShapeElement>, string> OnElementsUpdated; |
| | | #endregion |
| | | |
| | | #region 图片缓存/保存 |
| | | readonly ConcurrentBag<ImageSet> _imageSetList = new ConcurrentBag<ImageSet>(); |
| | | //public readonly ConcurrentBag<IImageSet> _imageSetList = new ConcurrentBag<IImageSet>(); |
| | | protected Dictionary<string, IImageSet> _imageSetList = new Dictionary<string, IImageSet>(); |
| | | |
| | | public void NewImageSet(ImageSet set) |
| | | public void NewImageSet(IImageSet set) |
| | | { |
| | | set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage; |
| | | set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage; |
| | | set.IsAddtionalSaved = !string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType); |
| | | set.OnImageSetTimeout += ImageSet_OnImageSetTimeout; |
| | | _imageSetList.Add(set); |
| | | set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType); |
| | | //set.OnImageSetTimeout += ImageSet_OnImageSetTimeout; |
| | | _imageSetList[set.Id] = set; |
| | | } |
| | | |
| | | //public virtual async void UpdateFitElements(List<IShapeElement> eleList, string imgSetId) |
| | |
| | | |
| | | public virtual async void SaveOriginImage(Bitmap map, Bitmap showImage, string imgSetId) |
| | | { |
| | | Task.Run(() => |
| | | await Task.Run(() => |
| | | { |
| | | OnImageUpdated?.Invoke(this, showImage, imgSetId); |
| | | }); |
| | | |
| | | ImageSet set = _imageSetList.FirstOrDefault(u => u.Id == imgSetId); |
| | | IImageSet set = _imageSetList[imgSetId]; |
| | | |
| | | if (set == null) |
| | | return; |
| | |
| | | { |
| | | LogAsync(DateTime.Now, $"{set.Id}原图保存失败", ex.GetExceptionMessage()); |
| | | } |
| | | //finally |
| | | //{ |
| | | // set.IsOriginSaved = true; |
| | | //} |
| | | } |
| | | set.IsOriginSaved = true; |
| | | ClearImageSet(set); |
| | |
| | | if (eleList.Count > 0) |
| | | OnElementsUpdated?.BeginInvoke(this, eleList, imgSetId, null, null); |
| | | |
| | | ImageSet set = _imageSetList.FirstOrDefault(u => u.Id == imgSetId); |
| | | IImageSet set = _imageSetList[imgSetId]; |
| | | if (set == null) |
| | | return; |
| | | |
| | |
| | | { |
| | | await Task.Run(() => |
| | | { |
| | | ImageSet set = _imageSetList.FirstOrDefault(u => u.Id == imgSetId); |
| | | IImageSet set = _imageSetList[imgSetId]; |
| | | if (set == null) |
| | | return; |
| | | |
| | |
| | | }); |
| | | } |
| | | |
| | | private string CheckImageDirectory(string subDir, string prefix) |
| | | protected string CheckImageDirectory(string subDir, string prefix) |
| | | { |
| | | if (string.IsNullOrWhiteSpace(subDir)) |
| | | { |
| | |
| | | return imgDir; |
| | | } |
| | | |
| | | private void SaveImageByNameAndType(Bitmap map, string imageName, ImageFormat imgFormat, string imageDir) |
| | | protected void SaveImageByNameAndType(Bitmap map, string imageName, ImageFormat imgFormat, string imageDir) |
| | | { |
| | | string filePath = Path.Combine(imageDir, $"{imageName}.{imgFormat.ToString().ToLower()}"); |
| | | map.Save(filePath, imgFormat); |
| | |
| | | |
| | | //private Timer clearImageSetTimer = null; |
| | | |
| | | public void ClearImageSet(ImageSet set) |
| | | public virtual void ClearImageSet(IImageSet set) |
| | | { |
| | | try |
| | | { |
| | |
| | | // && (!set.ImageSaveOption.IsSaveNGImage || set.IsNGSaved)) |
| | | if (set.IsOriginSaved && set.IsFitSaved && set.IsAddtionalSaved) |
| | | { |
| | | _imageSetList.TryTake(out set); |
| | | set.Dispose(); |
| | | //LogAsync(DateTime.Now, $"移除图片信息,当前缓存数量:{_imageSetList.Count}", ""); |
| | | |
| | | _imageSetList.Remove(set.Id); |
| | | LogAsync(DateTime.Now, $"移除图片信息,当前缓存数量:{_imageSetList.Count}", ""); |
| | | } |
| | | //bool flag = false; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | public void ClearImageSet(string imgSetId) |
| | | { |
| | | ImageSet set = _imageSetList.First(u => u.Id == imgSetId); |
| | | if (set != null) |
| | | ClearImageSet(set); |
| | | } |
| | | //public void ClearImageSet(string imgSetId) |
| | | //{ |
| | | // IImageSet set = _imageSetList[imgSetId]; |
| | | // if (set != null) |
| | | // ClearImageSet(set); |
| | | //} |
| | | |
| | | private void ImageSet_OnImageSetTimeout(ImageSet set) |
| | | { |
| | | ClearImageSet(set); |
| | | } |
| | | //private void ImageSet_OnImageSetTimeout(ImageSet set) |
| | | //{ |
| | | // ClearImageSet(set); |
| | | //} |
| | | |
| | | //private void ClearImageSetPeriodically() |
| | | //{ |
| | |
| | | |
| | | private System.Threading.Timer clearImageTimer = null; |
| | | #endregion |
| | | |
| | | #region 图片转换 |
| | | [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] |
| | | public static extern void CopyMemory(IntPtr dest, IntPtr src, long count); |
| | | |
| | | protected async void Generate8GrayImageByPointer(int width, int height, IntPtr dataPtr, string imgSetId) |
| | | { |
| | | await Task.Run(() => |
| | | { |
| | | //************************Mono8 转 Bitmap******************************* |
| | | Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); |
| | | Bitmap showImage = new Bitmap(width, height, PixelFormat.Format8bppIndexed); |
| | | |
| | | ColorPalette cp = bmp.Palette; |
| | | for (int i = 0; i < 256; i++) |
| | | { |
| | | cp.Entries[i] = Color.FromArgb(i, i, i); |
| | | } |
| | | bmp.Palette = cp; |
| | | |
| | | ColorPalette cp1 = showImage.Palette; |
| | | for (int i = 0; i < 256; i++) |
| | | { |
| | | cp1.Entries[i] = Color.FromArgb(i, i, i); |
| | | } |
| | | showImage.Palette = cp1; |
| | | |
| | | long[] ptr = new long[3]; |
| | | Rectangle rect = new Rectangle(0, 0, width, height); |
| | | BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); |
| | | BitmapData showImageData = showImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); |
| | | int PixelSize = Bitmap.GetPixelFormatSize(bitmapData.PixelFormat) / 8; |
| | | |
| | | if (width % 4 == 0) |
| | | { |
| | | CopyMemory(bitmapData.Scan0, dataPtr, width * height * PixelSize); |
| | | CopyMemory(showImageData.Scan0, dataPtr, width * height * PixelSize); |
| | | } |
| | | else |
| | | { |
| | | ptr[0] = bitmapData.Scan0.ToInt64(); |
| | | ptr[1] = showImageData.Scan0.ToInt64(); |
| | | ptr[2] = (long)dataPtr; |
| | | for (int i = 0; i < height - 1; i++) |
| | | { |
| | | ptr[2] += width; |
| | | |
| | | CopyMemory((IntPtr)ptr[0], (IntPtr)ptr[2], width * PixelSize); |
| | | CopyMemory((IntPtr)ptr[1], (IntPtr)ptr[2], width * PixelSize); |
| | | ptr[0] += bitmapData.Stride; |
| | | ptr[1] += showImageData.Stride; |
| | | } |
| | | } |
| | | bmp.UnlockBits(bitmapData); |
| | | showImage.UnlockBits(showImageData); |
| | | |
| | | SaveOriginImage(bmp, showImage, imgSetId); |
| | | }); |
| | | } |
| | | |
| | | protected async Task Generate16GrayImageByPointer(int width, int height, IntPtr dataPtr, string imgSetId) |
| | | { |
| | | await Task.Run(() => |
| | | { |
| | | //Thread.Sleep(1000); |
| | | int widthIn4 = (int)Math.Ceiling(width / 4.0) * 4; |
| | | |
| | | Bitmap bmp = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb); |
| | | Bitmap showImage = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb); |
| | | |
| | | Rectangle rect = new Rectangle(0, 0, widthIn4, height); |
| | | BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb); |
| | | BitmapData showImageData = showImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb); |
| | | unsafe |
| | | { |
| | | byte* data = (byte*)dataPtr; |
| | | byte* bitmapBuffer = (byte*)bitmapData.Scan0; |
| | | byte* showBitmapBuffer = (byte*)showImageData.Scan0; |
| | | |
| | | //Parallel.For(0, height, i => |
| | | // { |
| | | // Parallel.For(0, width, j => |
| | | // { |
| | | // showBitmapBuffer[(i * widthIn4 + j) * 6] = bitmapBuffer[(i * widthIn4 + j) * 6] = data[(i * width + j) * 2]; |
| | | // showBitmapBuffer[(i * widthIn4 + j) * 6 + 1] = bitmapBuffer[(i * widthIn4 + j) * 6 + 1] = data[(i * width + j) * 2 + 1]; |
| | | // }); |
| | | // }); |
| | | |
| | | Parallel.For(0, width * height, i => |
| | | { |
| | | int index = (i + 1) % width + widthIn4 * ((i + 1) / width) - 1; |
| | | |
| | | showBitmapBuffer[index * 6] = bitmapBuffer[index * 6] = data[i * 2]; |
| | | showBitmapBuffer[index * 6 + 1] = bitmapBuffer[index * 6 + 1] = data[i * 2 + 1]; |
| | | }); |
| | | } |
| | | |
| | | bmp.UnlockBits(bitmapData); |
| | | showImage.UnlockBits(showImageData); |
| | | |
| | | SaveOriginImage(bmp, showImage, imgSetId); |
| | | }); |
| | | } |
| | | #endregion |
| | | } |
| | | |
| | | #region Config |
| | |
| | | [Category("取像配置")] |
| | | [Description("曝光")] |
| | | [DisplayName("曝光")] |
| | | public float Exposure |
| | | public virtual float Exposure |
| | | { |
| | | get => exposure; |
| | | set |
| | |
| | | [Category("取像配置")] |
| | | [Description("增益")] |
| | | [DisplayName("增益")] |
| | | public float Gain { get; set; } |
| | | public virtual float Gain { get; set; } |
| | | |
| | | [Category("取像配置")] |
| | | [Description("曝光修改后等待时间,单位ms。针对部分场景确保曝光修改及时生效。")] |
| | | [DisplayName("曝光等待")] |
| | | public int ExposureWaitTime { get; set; } |
| | | public virtual int ExposureWaitTime { get; set; } |
| | | |
| | | [Category("取像配置")] |
| | | [Description("拍摄后曝光值。可在一次拍摄后将曝光修改为下次拍摄的曝光值,节约曝光生效时间。")] |
| | | [DisplayName("拍摄后曝光")] |
| | | public float ExposureAfterSnap { get; set; } |
| | | public virtual float ExposureAfterSnap { get; set; } |
| | | |
| | | [Category("算法配置")] |
| | | [Description("算法路径")] |
| | |
| | | [Category("相机设置")] |
| | | [Description("相机IP地址")] |
| | | [DisplayName("相机IP地址")] |
| | | public string CameraIP { get; set; } |
| | | public virtual string CameraIP { get; set; } |
| | | |
| | | [Category("相机设置")] |
| | | [Description("上位机IP地址")] |
| | | [DisplayName("上位机IP地址")] |
| | | public string ComputerIP { get; set; } |
| | | public virtual string ComputerIP { get; set; } |
| | | |
| | | [Category("保存设置")] |
| | | [Description("图片保存目录")] |
| | | [DisplayName("图片保存目录")] |
| | | [Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))] |
| | | public string ImgDirectory { get; set; } = @"../Images"; |
| | | public virtual string ImgDirectory { get; set; } = @"../Images"; |
| | | |
| | | [Category("保存设置")] |
| | | [Description("图片保存天数")] |
| | | [DisplayName("图片保存天数")] |
| | | public int SaveImageDayLimit { get; set; } = 0; |
| | | public virtual int SaveImageDayLimit { get; set; } = 0; |
| | | |
| | | [Category("保存设置")] |
| | | [Description("图片保存默认配置,主要用于硬触发等没有明确操作配置说明的图片保存")] |
| | | [DisplayName("图片保存默认配置")] |
| | | [TypeConverter(typeof(ComplexObjectConvert))] |
| | | [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))] |
| | | public ImageSaveOption ImageSaveOption { get; set; } = new ImageSaveOption(); |
| | | public virtual ImageSaveOption ImageSaveOption { get; set; } = new ImageSaveOption(); |
| | | |
| | | [Category("拍摄设置")] |
| | | [Description("默认曝光值,相机开启后就设置该曝光值")] |
| | | [DisplayName("默认曝光值")] |
| | | public float DefaultExposure { get; set; } |
| | | public virtual float DefaultExposure { get; set; } |
| | | } |
| | | #endregion |
| | | |
| | | #region Converter & Editor |
| | | public class HalconSerialNumConverter : ComboBoxItemTypeConvert |
| | | { |
| | | public override Hashtable GetConvertHash() |
| | | public override Hashtable GetConvertHash(ITypeDescriptorContext context) |
| | | { |
| | | Hashtable table = new Hashtable(); |
| | | HTuple deviceList = null; |
| | |
| | | |
| | | public class CameraDeviceConverter : ComboBoxItemTypeConvert |
| | | { |
| | | public override Hashtable GetConvertHash() |
| | | public override Hashtable GetConvertHash(ITypeDescriptorContext context) |
| | | { |
| | | Hashtable table = new Hashtable(); |
| | | using (var scope = GlobalVar.Container.BeginLifetimeScope()) |
| | |
| | | } |
| | | } |
| | | |
| | | public class ImageSet : IDisposable |
| | | public interface IImageSet:IDisposable |
| | | { |
| | | DateTime InitialTime { get; set; } |
| | | string Id { get; } |
| | | HImage HImage { get; set; } |
| | | Bitmap Image { get; set; } |
| | | |
| | | object SaveLock { get; set; } |
| | | |
| | | ImageSaveOption ImageSaveOption { get; set; } |
| | | bool IsOriginSaved { get; set; } |
| | | bool IsFitSaved { get; set; } |
| | | bool IsAddtionalSaved { get; set; } |
| | | |
| | | //event Action<ImageSet> OnImageSetTimeout; |
| | | |
| | | /// <summary> |
| | | /// 序列化操作的图像信息 |
| | | /// </summary> |
| | | string ImageData { get; set; } |
| | | } |
| | | |
| | | public class ImageSet : IImageSet |
| | | { |
| | | public DateTime InitialTime { get; set; } = DateTime.Now; |
| | | |
| | |
| | | //public bool IsInvokeSaveNG { get; set; } = false; |
| | | public bool IsAddtionalSaved { get; set; } = false; |
| | | |
| | | public object SaveLock = new object(); |
| | | public object SaveLock { get; set; } = new object(); |
| | | |
| | | public event Action<ImageSet> OnImageSetTimeout; |
| | | private Timer autoDisposeTimer = null; |
| | | public virtual string ImageData { get; set; } |
| | | |
| | | private void OnAutoDispose(object state) |
| | | //public event Action<ImageSet> OnImageSetTimeout; |
| | | //private Timer autoDisposeTimer = null; |
| | | |
| | | public void Dispose(object state) |
| | | { |
| | | OnImageSetTimeout?.Invoke(this); |
| | | //OnImageSetTimeout?.Invoke(this); |
| | | |
| | | //autoDisposeTimer.Change(-1, -1); |
| | | //autoDisposeTimer.Dispose(); |
| | | |
| | | Image?.Dispose(); |
| | | Image = null; |
| | | } |
| | | |
| | | public virtual void Dispose() |
| | | { |
| | | Dispose(null); |
| | | } |
| | | |
| | | public ImageSet() |
| | | { |
| | | autoDisposeTimer = new Timer(OnAutoDispose, null, -1, 10 * 1000); |
| | | } |
| | | |
| | | public void Dispose() |
| | | { |
| | | autoDisposeTimer.Change(-1, -1); |
| | | autoDisposeTimer.Dispose(); |
| | | |
| | | Image?.Dispose(); |
| | | Image = null; |
| | | |
| | | HImage?.Dispose(); |
| | | HImage = null; |
| | | //autoDisposeTimer = new Timer(Dispose, null, 10 * 1000, -1); |
| | | } |
| | | #endregion |
| | | } |