using Cognex.VisionPro; using Cognex.VisionPro.ImageFile; //using Cognex.VisionPro.Interop; using Cognex.VisionPro.ToolBlock; using Cognex.VisionPro3D; using CSScripting; using Microsoft.Win32; using NPOI.SS.Formula.Functions; using SImagePro; using SR7Link; using SRAPI; using SRCSharpDemo; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using TeamAAS_VP.Enums; using TeamAAS_VP.Interfaces; using TeamAAS_VP.Models; namespace TeamAAS_VP.Core.Cameras { public class SSZNCamera : ICamera, INotifyPropertyChanged { #region 字段 private Thread m_hReceiveThread; // 用于序列化对同一相机实例的操作,防止同一实例被并发操作 //private readonly SemaphoreSlim _operationSemaphore = new SemaphoreSlim(1, 1); // 用于保护状态变量(例如 IsGrabbing)的并发访问 private readonly object _stateLock = new object(); //private SR7ApiOneTimeCallbackImpl iSR7APi = new SR7ApiOneTimeCallbackImpl(); private SR7ApiSyncCallbackImpl iSR7APi= new SR7ApiSyncCallbackImpl(); public SRCSharpTools srcsharpTools = new SRCSharpTools(); private SR7IFGetDataCallBack GetDataDelegate; private ErrConnectCallBack _errConnectDelegate; // 用于 Grab() 的一次性等待/完成通知 private TaskCompletionSource _grabTcs; private readonly SemaphoreSlim _grabSemaphore = new SemaphoreSlim(1, 1); private CancellationTokenSource _grabCts; #endregion #region define private int lastTotalPoints = 0; // 记录上次的总点数 / Record the last total points public int coutCallbackPoints;//统计总回调行数 / Count the total number of callback rows public uint profile16Bits = 0;//0:32bit 1:16bit //define public const int INVALID_VALUE_MIN = -1000000000; public const int INVALID_VALUE_MAX = 1000000000; #endregion #region Image cache variable //image cache public int[][] ImgBuff32; // 32-bit height data public short[][] ImgBuff16; // 16-bit height data public byte[][] GrayBuff; // Grayscale data public int[][] Encoder; // Encoder data public int coutCallbackPoints_B; #endregion #region 属性 /// /// 是否是3D相机 /// public bool Is3D { get; } = true; SImagePro.SPointCloudHead pcHead = new SImagePro.SPointCloudHead(0, 0, 0, 0, 0); public CameraBrand CameraBrand { get => CameraBrand.SSZN; } public string Name { get; private set; } public Guid ID { get; private set; } public int Index { get; set; } public string ManufacturerName { get; private set; } public bool IsFindByIp { get; private set; } public string ModelName { get; private set; } public string SerialNumber { get; private set; } public string CameraIp { get; private set; } public CameraType CameraType { get; private set; } public UInt32 ImageWidth { get; private set; } public UInt32 ImageHeight { get; private set; } private bool _IsGrabbing; /// /// 正在采集 /// public bool IsGrabbing { get { return _IsGrabbing; } private set { SetProperty(ref _IsGrabbing, value); } } private ICogImage _Image; public ICogImage Image { get { return _Image; } private set { SetProperty(ref _Image, value); } } private CogImage8Grey _Image2; public CogImage8Grey Image2 { get { return _Image2; } private set { SetProperty(ref _Image2, value); } } public bool IsConnected { get; private set; } /// /// 采集用时 /// public TimeSpan TotalTime { get; private set; } /// /// 错误信息 /// public string ErrorMessage { get; private set; } private bool _CameraRevFinish; /// /// 图像接收完成 /// public bool CameraRevFinish { get { return _CameraRevFinish; } set { SetProperty(ref _CameraRevFinish, value); } } /// /// 图像接收超时时间30s /// private double Timeout = 30; #endregion #region 事件 public event Action ImageCallbackEvent; public event Action CameraConnectChangedEvent; #endregion public SSZNCamera(Guid id, int index, string name, string serialNumber, string cameraip, bool isFindByIp) { ID = id; Name = serialNumber; Index = index; CameraIp = cameraip; SerialNumber = serialNumber; IsFindByIp = isFindByIp; IsConnected = false; } #region 方法 /// /// 外部设置批处理点数(例如从 UI 的 PlcPoint.Camera_Data) /// /// public void SetBatchPoints(int batchPoints) { // 保证线程安全 //_operationSemaphore.Wait(); try { try { // 如果 SDK 对象支持 BatchPoints 字段,则设置 iSR7APi.BatchPoints = batchPoints; iSR7APi.Init((int)iSR7APi.BatchPoints, 0, 2000, GetDataDelegate); } catch { } try { // 将值写回相机配置(保持与 OpenDevice 一致的行为) iSR7APi.SetParams(0, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.BATCH_POINT, batchPoints); //SR7LinkFunc.SR7IF_StartMeasureWithCallback(0, 1); } catch { } } finally { //_operationSemaphore.Release(); } } /// /// 外部设置批处理点数(例如从 UI 的 PlcPoint.Camera_Data) /// /// public void SetProducts(int CameraNum, int ProductPoints) { // 保证线程安全 //_operationSemaphore.Wait(); try { int err= SR7LinkFunc.SR7IF_SwitchProgram(CameraNum-1, ProductPoints); } finally { //_operationSemaphore.Release(); } } /// /// 获取设备 /// /// public static CameraInfo[] GetDevices() { List cameras = new List(); try { if (!CheckSoftwareInstalled().isInstalled) { LogHelper.WriteLogInfo("未安装MVS"); return cameras.ToArray(); } SR7ApiOneTimeCallbackImpl sR7Api = new SR7ApiOneTimeCallbackImpl(); List cameraIPs = new List(); if (!sR7Api.SearchCameraIP(out cameraIPs)) { return cameras.ToArray(); } else { for (int i = 0; i < cameraIPs.Count; i++) { cameras.Add(new CameraInfo() { CameraNo = i + 1, CameraName = "SSZN_" + cameraIPs[i], CameraBrand = CameraBrand.SSZN, CameraType = CameraType.GIGE, ManufacturerName = "SSZN", Model = "SSZN_Model", SerialNumber = "SSZN_SerialNumber", CameraIp = cameraIPs[i], IsFindByIp = true, }); } } } catch (Exception ex) { LogHelper.WriteLogError("搜索深视3D相机列表时出错!", ex); } return cameras.ToArray(); } /// /// 检查相机软件是否安装 /// /// public static (bool isInstalled, string version) CheckSoftwareInstalled() { return (true, ""); } /// /// 打开相机 /// /// /// public bool OpenDevice() { //_operationSemaphore.Wait(); try { if (!iSR7APi.CameraBOnline) { //SR7Link.ErrConnectCallBack ErrConnectDelegate = new SR7Link.ErrConnectCallBack(ErrConnectFunc); //ErrConnectDelegate = new ErrConnectCallBack(ErrConnectFunc); //int nOpenRet = iSR7APi.Open(Index - 1, CameraIp, 2000, ErrConnectDelegate); if(_errConnectDelegate==null) { _errConnectDelegate=new ErrConnectCallBack(ErrConnectFunc); } int nOpenRet = iSR7APi.Open(Index - 1, CameraIp, 2000, _errConnectDelegate); if (nOpenRet == (int)SR7Link.SR7IF_ERROR.SR7IF_OK) { //设置相机参数,否则无法取图 / Set the camera parameters, otherwise you will not be able to take pictures //一次回调和无限回调可以设置批处理测量On,批处理数据接收无和循环 / One-time callback and infinite callback can set batch measurement On, batch data receiving None and loop //异步回调必须在Ed软件中设置 / Asynchronous callbacks must be set in the EdgeImaging software int nReadBastchValue = -1; int nSetParamRet = -1; int getParamRet = iSR7APi.GetParams(Index - 1, -1, SR7IF_SETTING_ITEM.BATCH_ON_OFF, out nReadBastchValue); if (nReadBastchValue != 1) { //nSetParamRet = iSR7APi.SetParams(Index - 1, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.BATCH_ON_OFF, 1); LogHelper.WriteLogInfo($"Set Batch On Off: {nSetParamRet}"); } int _BatchPoints = 0; getParamRet = iSR7APi.GetParams(Index - 1, -1, SR7IF_SETTING_ITEM.BATCH_POINT, out _BatchPoints); iSR7APi.BatchPoints = _BatchPoints; //nSetParamRet = iSR7APi.SetParams(Index - 1, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.CYCLICAL_PATTERN, 0); //int nSetParamRet1 = iSR7APi.SetParams(Index - 1, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.SEGMENT_BUFER, 0); int nSetParamRet1 = iSR7APi.SetParams(Index - 1, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.SEGMENT_BUFER, 1); LogHelper.WriteLogInfo($"Set Batch Data Receive: {nSetParamRet1}{nSetParamRet1}"); coutCallbackPoints = 0; GetDataDelegate = new SR7IFGetDataCallBack(GetDataCallBack); //iSR7APi.Init(Index - 1, 0, 2000, GetDataDelegate); } LogHelper.WriteLogInfo($"Connect Camera {nOpenRet} {GetSDKErrMsgByCode(nOpenRet)}"); } if (!IsConnected) { if (iSR7APi.CameraAOnline) { CameraConnectChangedEvent?.Invoke(ID, true); } } IsConnected = iSR7APi.CameraAOnline; return IsConnected; } finally { //_operationSemaphore.Release(); } } /// /// 打开相机异步 /// /// public Task OpenDeviceAsync() { return Task.Run(() => { return OpenDevice(); }); } /// /// 关闭相机 /// public void CloseDevice() { // ch:关闭设备 | en:Close Device //_operationSemaphore.Wait(); try { if (iSR7APi == null) { return; } try { _grabCts?.Cancel(); } catch { } try { _grabTcs?.TrySetCanceled(); } catch { } iSR7APi.Stop(); int nRet = iSR7APi.Close(); LogHelper.WriteLogInfo($"Close Camera: {nRet}{GetSDKErrMsgByCode(nRet)}"); } finally { //_operationSemaphore.Release(); } } /// /// 采集图像(同步阻塞实现:发送一次启动,等待回调或超时,返回图像) /// /// public ICogImage Grab(bool isRealtime = true) { // 采用同步阻塞方式实现,一次采集等待回调完成或超时返回 //_operationSemaphore.Wait(); try { if (!isRealtime) return Image; DateTime now = DateTime.Now; while (!CameraRevFinish) { Thread.Sleep(10); if (DateTime.Now.Subtract(now).TotalSeconds > Timeout) { LogHelper.WriteLogDebug("图像采集超时"); return null; } } //SCV.Show3DImage(ImgBuff32[0], (int)pcHead.width, (int)pcHead.height,pcHead.xInterval,pcHead.yInterval); return Image; } catch (Exception ex) { LogHelper.WriteLogError("Grab 出错", ex); return null; } finally { _grabTcs = null; //_operationSemaphore.Release(); } } public ICogImage Grab2(bool isRealtime = true) { // 采用同步阻塞方式实现,一次采集等待回调完成或超时返回 //_operationSemaphore.Wait(); try { if (!isRealtime) return Image2; DateTime now = DateTime.Now; while (!CameraRevFinish) { Thread.Sleep(10); if (DateTime.Now.Subtract(now).TotalSeconds > Timeout) { LogHelper.WriteLogDebug("图像采集超时"); return null; } } return Image2; } catch (Exception ex) { LogHelper.WriteLogError("Grab 出错", ex); return null; } finally { _grabTcs = null; //_operationSemaphore.Release(); } } //public async Task GrabAsync(bool isRealtime = true, CancellationToken cancellationToken = default(CancellationToken)) //{ // if (!isRealtime) // return Image; // await _grabSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); // try // { // CameraRevFinish = false; // ErrorMessage = null; // coutCallbackPoints = 0; // _grabTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); // _grabCts?.Dispose(); // _grabCts = new CancellationTokenSource(TimeSpan.FromSeconds(Timeout)); // using (var linked = CancellationTokenSource.CreateLinkedTokenSource(_grabCts.Token, cancellationToken)) // using (linked.Token.Register(() => _grabTcs.TrySetCanceled(), useSynchronizationContext: false)) // { // var ret = iSR7APi.Start(false, (int)(Timeout * 1000)); // if (ret != 0) // { // ErrorMessage = GetSDKErrMsgByCode(ret); // return null; // } // return await _grabTcs.Task.ConfigureAwait(false); // } // } // catch (TaskCanceledException) // { // LogHelper.WriteLogDebug("图像采集超时/取消"); // return null; // } // catch (Exception ex) // { // LogHelper.WriteLogError("GrabAsync 出错", ex); // return null; // } // finally // { // _grabTcs = null; // _grabSemaphore.Release(); // } //} //public ICogImage Grab(bool isRealtime = true) //{ // try // { // return GrabAsync(isRealtime).GetAwaiter().GetResult(); // } // catch (Exception ex) // { // LogHelper.WriteLogError("Grab 出错", ex); // return null; // } //} #region Init Memory public void InitImageBufferMem(bool isExistCameraB, int nWidth, int nHeight) { int nTotalPoints = nWidth * nHeight; if (nTotalPoints <= 0 || nTotalPoints <= lastTotalPoints) { for (int i = 0; i < 2; i++) { for (int j = 0; j < nTotalPoints; j++) { ImgBuff32[i][j] = -1000000000; // 初始化为 -1000000000 } for (int j = 0; j < nTotalPoints; j++) { ImgBuff16[i][j] = 0; GrayBuff[i][j] = 0; } for (int j = 0; j < nHeight; j++) { Encoder[i][j] = 0; } } if (nTotalPoints == lastTotalPoints) { return; } // 避免重复初始化 / Avoid repeated initialization } // 如果 nTotalPoints 发生变化,才重新分配内存 // If nTotalPoints changes, reallocate memory FreeMemory(); ImgBuff32 = new int[2][]; ImgBuff16 = new short[2][]; GrayBuff = new byte[2][]; Encoder = new int[2][]; for (int i = 0; i < 2; i++) { ImgBuff32[i] = new int[nTotalPoints]; // 32-bit 高度数据 / height data for (int j = 0; j < nTotalPoints; j++) { ImgBuff32[i][j] = -1000000000; // 初始化为 -1000000000 } ImgBuff16[i] = new short[nTotalPoints]; // 16-bit 高度数据 / height data GrayBuff[i] = new byte[nTotalPoints]; // 灰度数据 / grayscale data Encoder[i] = new int[nHeight]; // 编码器数据 / Encoder data } lastTotalPoints = nTotalPoints; } public void FreeMemory() { if (ImgBuff32 != null) { ImgBuff32 = null; ImgBuff16 = null; GrayBuff = null; Encoder = null; lastTotalPoints = 0; GC.Collect(); } } #endregion /// /// 开始采集图像 /// public void StartGrabbing() { //lock (_stateLock) //{ // if (IsGrabbing) // return; // IsGrabbing = true; //} //m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true }; //m_hReceiveThread.Start(); } /// /// 停止采集图像 /// public void StopGrabbing() { //try //{ // lock (_stateLock) // { // IsGrabbing = false; // } // Thread.Sleep(1000); // if (m_hReceiveThread != null) // { // m_hReceiveThread.Abort(); // m_hReceiveThread = null; // } //} //catch (Exception) //{ //} } /// /// 设置曝光时间 /// /// /// public bool SetExposureTime(float ExposureTime) { //_operationSemaphore.Wait(); //try //{ // if (!mvCameraAcq.bIsOpened) // return false; // mvCameraAcq.ExposureTime = (double)ExposureTime; // return true; //} //finally //{ // _operationSemaphore.Release(); //} return true; } /// /// 获取曝光时间 /// /// public float GetExposureTime() { //_operationSemaphore.Wait(); //try //{ // if (!mvCameraAcq.bIsOpened) // return 0; // return (float)mvCameraAcq.ExposureTime; //} //finally //{ // _operationSemaphore.Release(); //} return 0; } /// /// 设置增益 /// /// /// public bool SetGain(float Gain) { //_operationSemaphore.Wait(); //try //{ // if (!mvCameraAcq.bIsOpened) // return false; // mvCameraAcq.AnalogGain = (double)Gain; // return true; //} //finally //{ // _operationSemaphore.Release(); //} return true; } /// /// 获取增益 /// /// public float GetGain() { //_operationSemaphore.Wait(); //try //{ // if (!mvCameraAcq.bIsOpened) // return 0; // return (float)mvCameraAcq.AnalogGain; //} //finally //{ // _operationSemaphore.Release(); //} return 0; } private void GetStreamThreadProc() { while (IsGrabbing) { try { Grab(); ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage,ID); } catch (Exception) { } Thread.Sleep(10); } IsGrabbing = false; } /// /// /// /// 单条轮廓宽度数据 / Returns a single contour width data /// 返回的批处理行数 / The number of rows in the batch returned /// 回调函数执行状态,根据不同模式自定义 / Callback function execution status, customized according to different modes /// 错误码,0无错误 / Error code, 0 no error /// Sync callback 0:32bit data, 1:16bit data public void GetDataCallBack(int nProfileWidth, int nHighlen, int nFlag, int nStatusCode, int ProfileBits) { profile16Bits = (uint)ProfileBits; if (nStatusCode == 0) { Console.WriteLine($"Into GetDataFunc W:{nProfileWidth},H:{nHighlen},ErrCode:{nStatusCode}({GetSDKErrMsgByCode(nStatusCode)})"); //这里拿到相机数据做显示,可以根据其他具体业务实现自己的逻辑 //The camera data is obtained here for display, and you can implement your own logic according to other specific businesses int nTempWidth = nProfileWidth;// iSR7APi.GetProfileDataWidth(); //双相机时,一次回调和异步回调nProfileWidth=3200,无限循环回调nProfileWidth=6400 //For dual cameras, nProfileWidth=3200 for one-time callback and asynchronous callback, and nProfileWidth=6400 for infinite loop callback //if (iSR7APi.CameraBOnline && m_callbackMode == 2)//双相机 / dual camera // nTempWidth /= 2; int offset = coutCallbackPoints * nTempWidth; //int offset = 0; //iSR7APi.BatchPoints = nHighlen; pcHead.width = (uint)nTempWidth; pcHead.height = (uint)iSR7APi.BatchPoints; pcHead.xInterval = iSR7APi.GetProfileData_XPitch(); pcHead.yInterval = iSR7APi.GetProfileData_XPitch(); //if (coutCallbackPoints != coutCallbackPoints_B) //{ InitImageBufferMem(iSR7APi.CameraAOnline, nProfileWidth, iSR7APi.BatchPoints); // //ShowRGBImage(ImgBuff32[0], pcHead, pictureBoxA); //} //else if(coutCallbackPoints==0) //{ // InitImageBufferMem(iSR7APi.CameraAOnline, nProfileWidth, iSR7APi.BatchPoints); //} // coutCallbackPoints_B = coutCallbackPoints; if (ProfileBits == 0) { // 这里仍然用 iSR7APi.GetData():它会从异步回调写入的 IntPtr 缓冲 Marshal.Copy 到托管数组 var tempHeightDataA = new int[nTempWidth * nHighlen]; var tempGrayDataA = new byte[nTempWidth * nHighlen]; iSR7APi.GetData(tempHeightDataA, tempGrayDataA, Encoder[0], nTempWidth, nHighlen, 0); InitImageBufferMem(iSR7APi.CameraAOnline, nTempWidth, iSR7APi.BatchPoints); var copyLen = nTempWidth * nHighlen; var totalLen = nTempWidth * iSR7APi.BatchPoints; if (offset + copyLen > totalLen) copyLen = Math.Max(0, totalLen - offset); if (copyLen > 0) { Array.Copy(tempHeightDataA, 0, ImgBuff32[0], offset, copyLen); Array.Copy(tempGrayDataA, 0, GrayBuff[0], offset, copyLen); } coutCallbackPoints += nHighlen; // 满一帧才创建 CogImage 并发布/完成 GrabAsync if (coutCallbackPoints >= iSR7APi.BatchPoints) { coutCallbackPoints = 0; pcHead = new SImagePro.SPointCloudHead(0, 0, 0, 0, 0); pcHead.width = (uint)nTempWidth; pcHead.height = (uint)iSR7APi.BatchPoints; pcHead.xInterval = iSR7APi.GetProfileData_XPitch(); pcHead.yInterval = iSR7APi.GetProfileData_XPitch(); var cogImage16Range = SSZNCognexParser.SSZNParser.LoadSSZN3DImage( ImgBuff32[0], (int)pcHead.width, (int)pcHead.height, pcHead.xInterval, pcHead.yInterval); SRCSharpTools sRCSharpTools = new SRCSharpTools(); var Image_BitMap = sRCSharpTools.ByteArrayToGrayBitmap(GrayBuff[0], (int)pcHead.width, (int)pcHead.height); Cognex.VisionPro.CogImage8Grey cogImage8Grey = new Cognex.VisionPro.CogImage8Grey(Image_BitMap); Image2 = cogImage8Grey; Image = cogImage16Range; CameraRevFinish = true; ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage, ID); _grabTcs?.TrySetResult(Image); // 关键:完成一帧后复位计数,避免下一次 offset 继续累加导致越界/错帧 } return; } else { short[] temp16bitDataA = new short[nTempWidth * nHighlen]; byte[] tempGrayDataA = new byte[nTempWidth * nHighlen]; iSR7APi.GetData(temp16bitDataA, tempGrayDataA, Encoder[0], (int)pcHead.width, (int)nHighlen, 0); Array.Copy(temp16bitDataA, 0, ImgBuff16[0], offset, nTempWidth * nHighlen); Array.Copy(tempGrayDataA, 0, GrayBuff[0], offset, nTempWidth * nHighlen); int[] showtemp16bitDataA = new int[pcHead.width * pcHead.height]; //ShowTiff16Data(ImgBuff16[0], showtemp16bitDataA); if (ImgBuff16 != null && ImgBuff16.Length != 0 && ImgBuff16[0] != null) { //ShowRGBImage(showtemp16bitDataA, pcHead, pictureBoxA); } } if (iSR7APi.CameraBOnline && ImgBuff32[1] != null) { if (ProfileBits == 0) { int[] tempHeightDataB = new int[nTempWidth * nHighlen]; byte[] tempGrayDataB = new byte[nTempWidth * nHighlen]; iSR7APi.GetData(tempHeightDataB, tempGrayDataB, Encoder[1], (int)pcHead.width, (int)nHighlen, 1); Array.Copy(tempHeightDataB, 0, ImgBuff32[1], offset, nTempWidth * nHighlen); Array.Copy(tempGrayDataB, 0, GrayBuff[1], offset, nTempWidth * nHighlen); //ShowRGBImage(ImgBuff32[1], pcHead, pictureBoxB); } else { short[] tempHeightDataB = new short[nTempWidth * nHighlen]; byte[] tempGrayDataB = new byte[nTempWidth * nHighlen]; iSR7APi.GetData(tempHeightDataB, tempGrayDataB, Encoder[1], (int)pcHead.width, (int)nHighlen, 1); Array.Copy(tempHeightDataB, 0, ImgBuff16[1], offset, nTempWidth * nHighlen); Array.Copy(tempGrayDataB, 0, GrayBuff[1], offset, nTempWidth * nHighlen); int[] showtemp16bitDataB = new int[pcHead.width * pcHead.height]; //ShowTiff16Data(ImgBuff16[1], showtemp16bitDataB); //ShowRGBImage(showtemp16bitDataB, pcHead, pictureBoxB); } } coutCallbackPoints += nHighlen; } else { Console.WriteLine($"Data CallBack Exception:{nStatusCode}({GetSDKErrMsgByCode(nStatusCode)})"); } } public void ErrConnectFunc(int dwDeviceId, int nErrCode) { LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{GetSDKErrMsgByCode(nErrCode)}"); iSR7APi.CameraAOnline = false; iSR7APi.CameraBOnline = false; //:1:Data overflow,3:Disconnect, 4:Wrong version //Non-asynchronous mode: -1 represents a general error, such as link failure, setup failure, data acquisition failure, etc., -1000; switch (nErrCode) { case 1: LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_1")}"); break; case 3: LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_3")}"); break; case 4: LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_3")}"); break; case -1: LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_N1")}"); break; default: break; } } public string GetSDKErrMsgByCode(int nErrCode) { string strErrMsg; switch ((SR7Link.SR7IF_ERROR)nErrCode) { case SR7IF_ERROR.SR7IF_ERROR_NOT_FOUND: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_NOT_FOUND"); break; case SR7IF_ERROR.SR7IF_ERROR_COMMAND: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_COMMAND"); break; case SR7IF_ERROR.SR7IF_ERROR_PARAMETER: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_PARAMETER"); break; case SR7IF_ERROR.SR7IF_ERROR_UNIMPLEMENTED: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_UNIMPLEMENTED"); break; case SR7IF_ERROR.SR7IF_ERROR_HANDLE: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_HANDLE"); break; case SR7IF_ERROR.SR7IF_ERROR_MEMORY: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_MEMORY"); break; case SR7IF_ERROR.SR7IF_ERROR_TIMEOUT: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_TIMEOUT"); break; case SR7IF_ERROR.SR7IF_ERROR_DATABUFFER: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_DATABUFFER"); break; case SR7IF_ERROR.SR7IF_ERROR_STREAM: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_STREAM"); break; case SR7IF_ERROR.SR7IF_ERROR_CLOSED: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_CLOSED"); break; case SR7IF_ERROR.SR7IF_ERROR_VERSION: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_VERSION"); break; case SR7IF_ERROR.SR7IF_ERROR_ABORT: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ABORT"); break; case SR7IF_ERROR.SR7IF_ERROR_ALREADY_EXISTS: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ALREADY_EXISTS"); break; case SR7IF_ERROR.SR7IF_ERROR_FRAME_LOSS: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_FRAME_LOSS"); break; case SR7IF_ERROR.SR7IF_ERROR_ROLL_DATA_OVERFLOW: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ROLL_DATA_OVERFLOW"); break; case SR7IF_ERROR.SR7IF_ERROR_ROLL_BUSY: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ROLL_BUSY"); break; case SR7IF_ERROR.SR7IF_ERROR_MODE: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_MODE"); break; case SR7IF_ERROR.SR7IF_ERROR_CAMERA_NOT_ONLINE: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_CAMERA_NOT_ONLINE"); break; case SR7IF_ERROR.SR7IF_ERROR: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR"); break; case SR7IF_ERROR.SR7IF_NORMAL_STOP: strErrMsg = srcsharpTools.GetTranslation("SR7IF_NORMAL_STOP"); break; case SR7IF_ERROR.SR7IF_OK: strErrMsg = ""; break; default: strErrMsg = ""; break; } return strErrMsg; } #endregion #region ECD生成CogImage16Range的方法 /// /// 根据Int[]生成CogImage16Range /// /// ECD数据源 /// 图像宽度 /// 图像高度 /// X方向分辨率 /// Y方向分辨率 /// ECD的Z方向分辨率 /// CogImage16Range的Z方向分辨率 /// 生成的CogImage16Range /// 报错讯息 public static string Create16Range(int[] iData, int iWidth, int iHeight, double iScaleX, double iScaleY, double iSrcScaleZ, double iDstScaleZ, out CogImage16Range oImg) { try { bool mNoOverSize = true; #region 获取CogImage16Grey对象信息 CogImage16Grey mSrcImg = new CogImage16Grey(iWidth, iHeight); ICogImage16PixelMemory mPm = mSrcImg.Get16GreyPixelMemory(CogImageDataModeConstants.ReadWrite, 0, 0, mSrcImg.Width, mSrcImg.Height); int mStride = mPm.Stride; #endregion #region Int[]数据转置写入CogImage16Grey的像素内存 unsafe { int* mSrcDataPtr = (int*)Marshal.UnsafeAddrOfPinnedArrayElement(iData, 0); ushort* mDstDataPtr = (ushort*)mPm.Scan0; int mSurcIndex, mDestIndex; double mCurValue; for (int y = 0; y < iHeight; y++) { for (int x = 0; x < mStride; x++) { mSurcIndex = y * iWidth + x; mDestIndex = y * mStride + x; if (x < iWidth) { if (mSrcDataPtr[mSurcIndex] <= -1000000000) { mDstDataPtr[mDestIndex] = (ushort)0; } else { mCurValue = 1.0 * mSrcDataPtr[mSurcIndex] * (iSrcScaleZ / iDstScaleZ) + 32768; //0<=>65535 if (ushort.MinValue <= mCurValue && mCurValue <= ushort.MaxValue) { mDstDataPtr[mDestIndex] = (ushort)(mCurValue); } else { mNoOverSize &= false; mDstDataPtr[mDestIndex] = (ushort)0; } } } else { mDstDataPtr[mDestIndex] = (ushort)0; } } } } #endregion #region 建立CogImage16Grey的初始坐标空间-Sensor3D CogTransform2DLinear mTf2D = new CogTransform2DLinear(); double mScalingX = Math.Round(1.0 / iScaleX); double mScalingY = Math.Round(1.0 / iScaleY); double mRotationX = 2 * Math.PI; double mRotationY = 2 * Math.PI; double mTranslationX = 0d; double mTranslationY = 0d; mTf2D.SetScalingsRotationsTranslation(mScalingX, mScalingY, mRotationX, mRotationY, mTranslationX, mTranslationY); CogAddSpaceConstants mSpaceConstants = CogAddSpaceConstants.DuplicateIsError; mSrcImg.CoordinateSpaceTree.AddSpace("@", "Sensor2D", mTf2D, true, mSpaceConstants); #endregion #region 建立CogImage16Range的初始坐标空间-Sensor3D Cog3DMatrix3x3 m3DMatrix3x3 = new Cog3DMatrix3x3(iScaleX, 0, 0, 0, iScaleY, 0, 0, 0, iDstScaleZ); Cog3DVect3 m3DVect3 = new Cog3DVect3(-21, 0, 0); Cog3DTransformLinear mTf3D = new Cog3DTransformLinear(m3DMatrix3x3, m3DVect3); mTf3D = mTf3D.Inverse(); #endregion oImg = new CogImage16Range(mSrcImg, 0, mTf3D); #region 判断是否存在像素值超限情况 if (!mNoOverSize) { return "存在像素值超限情况"; } else { return null; } #endregion } catch (Exception ex) { oImg = null; return ex.Message; } } /// /// 读取ECD格式文件的图像数据 /// /// 文件路径 /// 图像数据 /// 图像宽度 /// 图像高度 /// X方向分辨率 /// Y方向分辨率 /// 报错讯息 public static string OpenEcd(string iFileName, out int[] oData, out int oWidth, out int oHeight, out double oScaleX, out double oScaleY) { try { #region 输出参数初始化 oData = null; oWidth = 0; oHeight = 0; oScaleX = 0; oScaleY = 0; #endregion #region 文件存在判断 if (!File.Exists(iFileName)) { return "文件不存在"; } #endregion #region 文件格式一致性判断 string mExtension = Path.GetExtension(iFileName); if (mExtension != ".ecd") { return "文件格式不一致不存在"; } #endregion #region 读取图像信息和数据 #region 依据文件流创建二进制流读取器 FileStream mFs = new FileStream(iFileName, FileMode.Open, FileAccess.Read); BinaryReader mBr = new BinaryReader(mFs); #endregion #region 文件头读取-获取点云规格(文件头共10240字节) uint mVersion = mBr.ReadUInt32(); int mWidth = mBr.ReadInt32(); int mHeight = mBr.ReadInt32(); int mStride = ((mWidth + 3) / 4) * 4; if (mVersion == 2) { oScaleX = Math.Round(mBr.ReadDouble(), 3); oScaleY = Math.Round(mBr.ReadDouble(), 3); Int32 _Type = mBr.ReadInt32(); //无效位,为了数据对齐 } else { Int32 _Type = mBr.ReadInt32(); //无效位,为了数据对齐 oScaleX = Math.Round(mBr.ReadDouble(), 3); oScaleY = Math.Round(mBr.ReadDouble(), 3); } //读取剩余文件头 mBr.ReadBytes(2552 * 4); #endregion oData = new int[mStride * mHeight]; #region 图像高度数据读取 unsafe { int* mDataPtr = (int*)Marshal.UnsafeAddrOfPinnedArrayElement(oData, 0); for (int y = 0; y < mHeight; y++) { for (int x = 0; x < mStride; x++) { if (x < mWidth) { mDataPtr[y * mStride + x] = mBr.ReadInt32(); } else { mDataPtr[y * mStride + x] = -1000000000; } } } } #endregion oWidth = mStride; oHeight = mHeight; #region 关闭文件流和读取器 mFs.Flush(); mFs.Close(); mBr.Close(); #endregion #endregion return null; } catch (Exception ex) { oData = null; oWidth = 0; oHeight = 0; oScaleX = 0; oScaleY = 0; return ex.Message; } } /// /// 保存Vpro的IDB格式图像 /// /// 图像对象 /// 保存路径 /// public string SaveToIdb(ICogImage iImg, string iPath) { try { CogImageFile _MyImageFile = new CogImageFile(); _MyImageFile.Open(iPath, CogImageFileModeConstants.Write); _MyImageFile.Append(iImg); _MyImageFile.Close(); return null; } catch (Exception ex) { return ex.Message; } } #endregion #region 属性通知 /// /// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; /// /// Checks if a property already matches a desired value. Sets the property and /// notifies listeners only when necessary. /// /// Type of the property. /// Reference to a property with both getter and setter. /// Desired value for the property. /// Name of the property used to notify listeners. This /// value is optional and can be provided automatically when invoked from compilers that /// support CallerMemberName. /// True if the value was changed, false if the existing value matched the /// desired value. protected virtual bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(storage, value)) return false; storage = value; RaisePropertyChanged(propertyName); return true; } /// /// Checks if a property already matches a desired value. Sets the property and /// notifies listeners only when necessary. /// /// Type of the property. /// Reference to a property with both getter and setter. /// Desired value for the property. /// Name of the property used to notify listeners. This /// value is optional and can be provided automatically when invoked from compilers that /// support CallerMemberName. /// Action that is called after the property value has been changed. /// True if the value was changed, false if the existing value matched the /// desired value. protected virtual bool SetProperty(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(storage, value)) return false; storage = value; onChanged?.Invoke(); RaisePropertyChanged(propertyName); return true; } /// /// Raises this object's PropertyChanged event. /// /// Name of the property used to notify listeners. This /// value is optional and can be provided automatically when invoked from compilers /// that support . protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } /// /// Raises this object's PropertyChanged event. /// /// The PropertyChangedEventArgs protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) { PropertyChanged?.Invoke(this, args); } #endregion } }