| | |
| | | using LB_SmartVisionCameraSDK.PHM6000; |
| | | using LB_SmartVisionCommon; |
| | | using LB_VisionProcesses.Cameras; |
| | | using OpenCvSharp; |
| | | using OpenCvSharp.Extensions; |
| | | using OpenVinoSharp.Extensions.model; |
| | | using SharpCompress.Common; |
| | | using Sunny.UI.Win32; |
| | |
| | | |
| | | // 初始化并注册采集回调 (获取数据用) |
| | | _acquisitionCallback = new AcquisitionCallbackZA(OnAcquisitionCallbackZA); |
| | | PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, _acquisitionCallback, IntPtr.Zero); |
| | | PHM6000Profiler.SetAcquisitionCallbackZA(_cameraHandle, _acquisitionCallback, new IntPtr()); |
| | | |
| | | // 初始化并注册采集完成回调 (状态通知用) |
| | | _acquisitionCompletedCallback = new AcquisitionCompletedCallback(OnAcquisitionCompleted); |
| | | PHM6000Profiler.RegisterAcquisitionCompletedCallback(_cameraHandle, _acquisitionCompletedCallback, IntPtr.Zero); |
| | | _acquisitionCompletedCallback += OnAcquisitionCompleted; |
| | | PHM6000Profiler.RegisterAcquisitionCompletedCallback(_cameraHandle, _acquisitionCompletedCallback, new IntPtr()); |
| | | |
| | | // 强制应用当前配置(确保触发模式等参数正确,避免相机处于未知状态) |
| | | UpdateSensorConfig(_sensorConfig); |
| | |
| | | config = new CameraConfig(null); |
| | | //UpdateSensorConfig(config); |
| | | } |
| | | public override bool GetImage(out Bitmap bitmap, int outtime = 14500) |
| | | public override bool GetImage(out Bitmap bitmap, int outtime = 14500) |
| | | { |
| | | bitmap = null; |
| | | try |
| | |
| | | } |
| | | } |
| | | } |
| | | private Bitmap bitmap1; |
| | | private int nWidth = 0, nHeight = 0; |
| | | |
| | | private void OnAcquisitionCompleted(IntPtr pInstance, int nOption) |
| | | { |
| | |
| | | } |
| | | else if (nOption == 2) |
| | | { |
| | | AsyncLogHelper.Info($"LBCamera[{SN}]: Processing End..."); |
| | | IntPtr INTPTRImage = PHM6000Profiler.GetIntensityData(_cameraHandle, ref nWidth, ref nHeight); |
| | | bitmap1 = IntensityPtrToMatCloned(INTPTRImage, nWidth, nHeight); |
| | | } |
| | | } |
| | | |
| | | public Bitmap ConvertIntensityToBitmap(IntPtr dataPtr, int width, int height) |
| | | { |
| | | |
| | | if (dataPtr == IntPtr.Zero || width <= 0 || height <= 0) |
| | | throw new InvalidOperationException("获取强度数据失败或尺寸无效。"); |
| | | |
| | | // 创建 8bpp 索引位图 |
| | | Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed); |
| | | |
| | | // 设置灰度调色板(必须,否则显示异常) |
| | | ColorPalette palette = bitmap.Palette; |
| | | for (int i = 0; i < 256; i++) |
| | | { |
| | | palette.Entries[i] = Color.FromArgb(i, i, i); |
| | | } |
| | | bitmap.Palette = palette; |
| | | |
| | | // 锁定位图数据 |
| | | BitmapData bmpData = bitmap.LockBits( |
| | | new Rectangle(0, 0, width, height), |
| | | ImageLockMode.WriteOnly, |
| | | PixelFormat.Format8bppIndexed); |
| | | |
| | | try |
| | | { |
| | | int srcStride = width; // 源数据每行字节数(无填充) |
| | | int dstStride = bmpData.Stride; // 位图每行字节数(可能对齐) |
| | | int copyBytesPerRow = Math.Min(srcStride, dstStride); |
| | | |
| | | IntPtr srcRowPtr = dataPtr; |
| | | IntPtr dstRowPtr = bmpData.Scan0; |
| | | |
| | | // 逐行复制,处理可能的步幅差异 |
| | | for (int y = 0; y < height; y++) |
| | | { |
| | | // 使用 Buffer.MemoryCopy 或 Marshal.Copy 按行复制 |
| | | unsafe |
| | | { |
| | | Buffer.MemoryCopy( |
| | | srcRowPtr.ToPointer(), |
| | | dstRowPtr.ToPointer(), |
| | | dstStride, // 目标缓冲区剩余大小(至少一行) |
| | | copyBytesPerRow); // 实际复制字节数 |
| | | } |
| | | |
| | | // 移动到下一行 |
| | | srcRowPtr = IntPtr.Add(srcRowPtr, srcStride); |
| | | dstRowPtr = IntPtr.Add(dstRowPtr, dstStride); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | bitmap.UnlockBits(bmpData); |
| | | } |
| | | |
| | | return bitmap; |
| | | } |
| | | |
| | | |
| | | public static Bitmap IntensityPtrToMatCloned(IntPtr dataPtr, int width, int height) |
| | | { |
| | | |
| | | if (dataPtr == IntPtr.Zero || width <= 0 || height <= 0) |
| | | { |
| | | throw new Exception("Failed to get intensity data."); |
| | | } |
| | | |
| | | // 先创建引用外部数据的 Mat |
| | | using (Mat temp = Mat.FromPixelData(height, width, MatType.CV_8UC1, dataPtr, width)) |
| | | { |
| | | // 克隆一份独立内存的 Mat |
| | | return temp.ToBitmap(); |
| | | } |
| | | } |
| | | |
| | |
| | | bmp.UnlockBits(bmpData); |
| | | bmpData = null; // 标记已解锁 |
| | | |
| | | |
| | | |
| | | _frameCount++; |
| | | AsyncLogHelper.Info($"LBCamera[{SN}]: 生成第 {_frameCount} 帧 ({width}x{height})"); |
| | | AsyncLogHelper.Info($"LBCamera[{SN}]: 生成第 {_frameCount} 帧 ({nWidth}x{nHeight})"); |
| | | |
| | | // 3. 获取/创建线程安全队列 |
| | | var queue = CollectedImages.GetOrAdd(SN, new ConcurrentQueue<Bitmap>()); |
| | |
| | | // 强制资源释放,绝对杜绝泄漏 |
| | | if (bmpData != null) |
| | | { |
| | | try { bmp?.UnlockBits(bmpData); } catch { } |
| | | try { bitmap1?.UnlockBits(bmpData); } catch { } |
| | | } |
| | | // 注意:bmp 已入队,不能在这里释放,由调用者释放 |
| | | //注意:bmp 已入队,不能在这里释放,由调用者释放 |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | if (Enum.TryParse(typeof(EnumNameId), p.Name, out object nameIdObj)) |
| | | { |
| | | EnumNameId nameId = (EnumNameId)nameIdObj; |
| | | //EnumNameId nameId = (EnumNameId)nameIdObj; |
| | | var nameId = Enum.Parse(typeof(EnumNameId), p.Name); |
| | | int intValue = 0; |
| | | double doubleValue = 0; |
| | | int enumValue = 0; |
| | | var id = Convert.ToInt32(nameId); |
| | | var rst = PHM6000Profiler.GetProfilerParameter(_cameraHandle, id, ref intValue, ref doubleValue, ref enumValue); |
| | | |
| | | if (PHM6000Profiler.GetProfilerParameter(_cameraHandle, (int)nameId, ref intValue, ref doubleValue, ref enumValue) == 0) |
| | | |
| | | if (rst == 0) |
| | | { |
| | | if (p.PropertyType == typeof(int)) |
| | | { |
| | |
| | | } |
| | | else // Enum or other types |
| | | { |
| | | p.SetValue(_sensorConfig, enumValue); |
| | | if (p.Name.Equals("ROI")) |
| | | { |
| | | |
| | | } |
| | | else |
| | | { |
| | | p.SetValue(_sensorConfig, enumValue); |
| | | } |
| | | } |
| | | } |
| | | } |