using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Threading; using System.Diagnostics; using Extensometer.Model.RequestModel; using Extensometer.Model.ResultModel; using Extensometer.BLL; using ThridLibray; namespace LineMeasurementLib { public class ImageLinePosition { public short left; public short top; public short right; public short bottom; } /// /// 像素间距识别算法 /// public class LineMeasure:IDisposable { #region 变量、类和对象 private static LineMeasure lineMeasure = null; //识别列表 public Queue BitmapList = new Queue(); //识别结果列表 public Queue ProcessResult = new Queue(); public Mutex m_mutex = new Mutex(); Thread ProcessThread = null; public float FirstPointLength = 0; //记录第一个结果点; public Stopwatch LineMessSW = null; #endregion #region 方法 /// /// 释放 /// public void Dispose() { Release(); } /// /// 构造方法 /// private LineMeasure() { _lmInitPara.stLineDetPara = new LM_LINEDET_PARA_S[LM_LINE_NUM_MAX]; } /// /// 提供给外部获取实例的方法 /// /// public static LineMeasure GetLineMeasure() { if (lineMeasure == null) { lineMeasure = new LineMeasure(); } return lineMeasure; } /// /// 算法初始化 /// /// /// /// public int Init(string cfgFile, string distFile) { //AllocConsole(); LoadConfigFile(cfgFile); LoadDistortionPara(distFile); WriteLine("Init Start", ConsoleColor.DarkGreen); _handle = LM_LineMeasureInit(ParaStructToPtr(_lmInitPara), 0); if (_distortionPara.iFlagEnable == 1) { LM_DistortionCalibSet(_handle, _distortionPara); } return 1; } /// /// 算法初始化 /// /// /// /// public int Init(RequestConfigParameterModel parameterModel, string distFile) { //AllocConsole(); LoadConfigFile(parameterModel); LoadDistortionPara(distFile); WriteLine("Init Start", ConsoleColor.DarkGreen); _handle = LM_LineMeasureInit(ParaStructToPtr(_lmInitPara), 0); if (_distortionPara.iFlagEnable == 1) { LM_DistortionCalibSet(_handle, _distortionPara); } return 1; } /// /// 算法初始化-返回配置文件范围选择 /// /// /// /// /// public int Init(string cfgFile, string distFile, ref List LinePositionList) { AllocConsole(); LoadConfigFile(cfgFile, ref LinePositionList); LoadDistortionPara(distFile); WriteLine("Init Start", ConsoleColor.DarkGreen); _handle = LM_LineMeasureInit(ParaStructToPtr(_lmInitPara), 0); if (_distortionPara.iFlagEnable == 1) { LM_DistortionCalibSet(_handle, _distortionPara); } return 1; } IntPtr ptr; LM_RULT_S res; /// /// 算法运行并返回结果 /// /// 图片byte /// /// /// public LM_RULT_S Process(byte[] grayimg, int width, int height) { ptr = ResultToPtr(_result); res = new LM_RULT_S(); if (B_ThreadProcess == false) { res.rultnum = 0; return res; } try { if (LM_LineMeasureProcess(_handle, grayimg, width, height, ptr) > 0) { _result = PtrToResult(ptr); if (_calibrationRes.iFlagSuccess == 1) { _result.LinePhysicaldis1 = _result.LinePixeldis1 * _calibrationRes.fConvertCoefficient; _result.LinePhysicaldis2 = _result.LinePixeldis2 * _calibrationRes.fConvertCoefficient; } else { _result.LinePhysicaldis1 = 0; _result.LinePhysicaldis2 = 0; } Marshal.FreeHGlobal(pP1); return _result; } } catch { //日志写入处 } res.rultnum = 0; return res; } /// /// 算法释放 /// public void Release() { LM_LineMeasureRelease(_handle); } /// /// 加载配置文件 /// /// public void LoadDistortionPara(String file) { FileStream fs = File.OpenRead(file); StreamReader sr = new StreamReader(fs); string line = sr.ReadLine(); var header = line.Split(new char[] { ' ' }); if (header != null && header.Length > 0) { var enable = int.Parse(header[0]); _distortionPara.iFlagEnable = enable; if (enable == 0) return; _distortionPara.iImgWidth = int.Parse(header[1]); _distortionPara.iImgHeight = int.Parse(header[2]); line = sr.ReadLine(); var camMat = line.Split(new char[] { ' ' }); for (int i = 0; i < 6; i++) { _distortionPara.fCammatrix[i] = double.Parse(camMat[i]); } line = sr.ReadLine(); var paraK = line.Split(new char[] { ' ' }); for (int i = 0; i < 3; i++) { _distortionPara.fDisK[i] = double.Parse(paraK[i]); } line = sr.ReadLine(); var paraP = line.Split(new char[] { ' ' }); for (int i = 0; i < 2; i++) { _distortionPara.fDisP[i] = double.Parse(paraP[i]); } line = sr.ReadLine(); var corrPara = line.Split(new char[] { ' ' }); for (int i = 0; i < 6; i++) { _distortionPara.fNewcammatInv[i] = double.Parse(corrPara[i]); } sr.Close(); fs.Close(); } else { sr.Close(); fs.Close(); return; } } /// /// 加载识别配置参数(文件) /// /// public void LoadConfigFile(String file) { _lmInitPara.iLineDetNum = int.Parse(ReadString("Config", "linedetnum", "0", file)); _lmInitPara.paraimgw = int.Parse(ReadString("Config", "imgw", "0", file)); _lmInitPara.paraimgh = int.Parse(ReadString("Config", "imgh", "0", file)); _lmInitPara.eLineDisMode = (LM_LINEDIS_MODE_E)int.Parse(ReadString("Config", "dismode", "0", file)); _calibrationRes.iFlagSuccess = int.Parse(ReadString("Config", "calibsuccess", "0", file)); _calibrationRes.fConvertCoefficient = float.Parse(ReadString("Config", "calibcoeff", "0.0", file)); for (int i = 0; i < _lmInitPara.iLineDetNum; i++) { _lmInitPara.stLineDetPara[i].stRoirectpara.left = short.Parse(ReadString("Config", "left" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].stRoirectpara.top = short.Parse(ReadString("Config", "top" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].stRoirectpara.right = short.Parse(ReadString("Config", "right" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].stRoirectpara.bottom = short.Parse(ReadString("Config", "bottom" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].stRoirect = _lmInitPara.stLineDetPara[i].stRoirectpara; _lmInitPara.stLineDetPara[i].eGrayDir = (LM_LINE_GRAYDIR_E)int.Parse(ReadString("Config", "eGrayDir" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].eLineDirection = (LM_LINE_DIRECTION_E)int.Parse(ReadString("Config", "eLineDirection" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].eLineOrder = (LM_LINE_ORDER_E)int.Parse(ReadString("Config", "eLineOrder" + i.ToString(), "0", file)); } return; } /// /// 加载识别配置参数(类) /// /// public ResultModel LoadConfigFile(RequestConfigParameterModel file) { ResultModel result = new ResultModel(); _lmInitPara.iLineDetNum = file.iLineDetNum; _lmInitPara.paraimgw = file.paraimgw; _lmInitPara.paraimgh = file.paraimgh; _lmInitPara.eLineDisMode = (LM_LINEDIS_MODE_E)file.eLineDisMode; _calibrationRes.iFlagSuccess = file.iFlagSuccess; _calibrationRes.fConvertCoefficient = file.fConvertCoefficient; for (int i = 0; i < _lmInitPara.iLineDetNum; i++) { _lmInitPara.stLineDetPara[i].stRoirectpara.left = file.stLineDetParas[i].LeftValue; _lmInitPara.stLineDetPara[i].stRoirectpara.top = file.stLineDetParas[i].TopValue; _lmInitPara.stLineDetPara[i].stRoirectpara.right = file.stLineDetParas[i].RightValue; _lmInitPara.stLineDetPara[i].stRoirectpara.bottom = file.stLineDetParas[i].BottomValue; _lmInitPara.stLineDetPara[i].stRoirect = _lmInitPara.stLineDetPara[i].stRoirectpara; _lmInitPara.stLineDetPara[i].eGrayDir = (LM_LINE_GRAYDIR_E)file.stLineDetParas[i].eGrayDir; _lmInitPara.stLineDetPara[i].eLineDirection = (LM_LINE_DIRECTION_E)file.stLineDetParas[i].eLineDirection; _lmInitPara.stLineDetPara[i].eLineOrder = (LM_LINE_ORDER_E)file.stLineDetParas[i].eLineOrder; } return result; } /// /// 加载配置文件并返回数据 /// /// /// public void LoadConfigFile(String file, ref List linePositions) { _lmInitPara.iLineDetNum = int.Parse(ReadString("Config", "linedetnum", "0", file)); _lmInitPara.paraimgw = int.Parse(ReadString("Config", "imgw", "0", file)); _lmInitPara.paraimgh = int.Parse(ReadString("Config", "imgh", "0", file)); _lmInitPara.eLineDisMode = (LM_LINEDIS_MODE_E)int.Parse(ReadString("Config", "dismode", "0", file)); _calibrationRes.iFlagSuccess = int.Parse(ReadString("Config", "calibsuccess", "0", file)); _calibrationRes.fConvertCoefficient = float.Parse(ReadString("Config", "calibcoeff", "0.0", file)); for (int i = 0; i < _lmInitPara.iLineDetNum; i++) { _lmInitPara.stLineDetPara[i].stRoirectpara.left = short.Parse(ReadString("Config", "left" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].stRoirectpara.top = short.Parse(ReadString("Config", "top" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].stRoirectpara.right = short.Parse(ReadString("Config", "right" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].stRoirectpara.bottom = short.Parse(ReadString("Config", "bottom" + i.ToString(), "0", file)); linePositions.Add(new ImageLinePosition { left = _lmInitPara.stLineDetPara[i].stRoirectpara.left, right = _lmInitPara.stLineDetPara[i].stRoirectpara.right, top = _lmInitPara.stLineDetPara[i].stRoirectpara.top, bottom = _lmInitPara.stLineDetPara[i].stRoirectpara.bottom }); _lmInitPara.stLineDetPara[i].stRoirect = _lmInitPara.stLineDetPara[i].stRoirectpara; _lmInitPara.stLineDetPara[i].eGrayDir = (LM_LINE_GRAYDIR_E)int.Parse(ReadString("Config", "eGrayDir" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].eLineDirection = (LM_LINE_DIRECTION_E)int.Parse(ReadString("Config", "eLineDirection" + i.ToString(), "0", file)); _lmInitPara.stLineDetPara[i].eLineOrder = (LM_LINE_ORDER_E)int.Parse(ReadString("Config", "eLineOrder" + i.ToString(), "0", file)); } return; } #endregion #region 线程方法 /// /// 识别线程运行控制变量 /// private bool B_ThreadProcess = false; /// /// 识别线程方法 /// private void ThreadProcess() { IdentifResultClass identifResult = new IdentifResultClass(); IdentifResultClass Ident = new IdentifResultClass(); while (B_ThreadProcess) { if (BitmapList.Count == 0) { Thread.Sleep(10); continue; } lock(this) { Ident = BitmapList.Dequeue(); } if (BitmapList.Count > 10) { LOG.error("ThreadProcess-BitmapList数据异常抛出,帧丢弃"); BitmapList.Clear(); } if (Ident == null) continue; LM_RULT_S result = new LM_RULT_S(); LineMessSW = new Stopwatch(); LineMessSW.Start(); result = lineMeasure.Process(Ident.ImageByte, Ident.ImageBitMap.Width, Ident.ImageBitMap.Height); LineMessSW.Stop(); //有无结果都返回 if (identifResult.LinePixeldis2 == 0 && result.LinePixeldis2 != 0) { FirstPointLength = result.LinePixeldis2; } identifResult = new IdentifResultClass() { ImageBitMap = Ident.ImageBitMap, ImageByte = Ident.ImageByte, ImageTime = Ident.ImageTime, Rultnum = result.rultnum, Displacement = (identifResult.LinePixeldis2 == 0 && identifResult.Displacement == 0) ? 0 : result.LinePixeldis2 - identifResult.LinePixeldis1, StrainValue = (identifResult.LinePixeldis2 == 0 && identifResult.StrainValue == 0) ? 0 : result.LinePixeldis2 - FirstPointLength, Distance = result.LinePixeldis2, LinePixeldis1 = result.LinePixeldis1, LinePhysicaldis1 = result.LinePhysicaldis1, LinePixeldis2 = result.LinePixeldis2, LinePhysicaldis2 = result.LinePhysicaldis2, IsFunction = true }; ProcessResult.Enqueue(identifResult); } } /// /// 识别线程开启 /// public void ProcessStart() { //修改识别标志量,代表开始识别 B_ThreadProcess = true; if (lineMeasure != null) { //加载配置文件 lineMeasure.Init(@AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "lm_config.ini", @AppDomain.CurrentDomain.SetupInformation.ApplicationBase+"coffrate.txt"); } //赋予ProcessThread线程方法 ProcessThread = new Thread(ThreadProcess); //清空待识别队列和识别结果队列 ProcessResult.Clear(); BitmapList.Clear(); //运行线程 ProcessThread.Start(); } /// /// 识别线程开启 /// public void ProcessStart(RequestConfigParameterModel parameterModel) { //修改识别标志量,代表开始识别 B_ThreadProcess = true; if (lineMeasure != null) { //加载配置文件 lineMeasure.Init(parameterModel, @AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "coffrate.txt"); //lineMeasure.Init(parameterModel, @".\coffrate.txt"); } //赋予ProcessThread线程方法 ProcessThread = new Thread(ThreadProcess); //清空待识别队列和识别结果队列 ProcessResult.Clear(); BitmapList.Clear(); //运行线程 ProcessThread.Start(); } /// /// 识别线程关闭 /// public void ProcessStop() { B_ThreadProcess = false; lineMeasure.Dispose(); } public bool GetThreadProcessStatic() { return B_ThreadProcess; } #endregion #region C++ 算法变量、结构体 public const int LM_LINE_NUM_MAX = 4; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LM_RECT_S { public short left; public short top; public short right; public short bottom; } public enum LM_LINE_GRAYDIR_E : Int32 { LINE_GRAYDIR_DEFAULT = 0, //不确定;默认由浅及深; LINE_GRAYDIR_SHALLOWTODEEP, //由浅及深; LINE_GRAYDIR_DEEPTOSHALLOW //由深及浅; } public enum LM_LINE_DIRECTION_E : Int32 { LINE_DIR_DEFAULT = 0, //默认为水平方向直线; LINE_DIR_HORIZONTAL, //水平方向直线; LINE_DIR_VERTICAL //竖直方向直线; } public enum LM_LINE_ORDER_E : Int32 { LINE_ORDER_DEFAULT = 0, //默认第一条线; LINE_ORDER_FIRSTLINE, //第一条线 LINE_ORDER_BESTLINE, //最佳线 LINE_ORDER_LASTLINE //最后一条线; } public enum LM_LINEDIS_MODE_E : Int32 { LINE_DISMODE_DEFAULT = 0, LINE_DISMODE_CNTTOCNT, //中点到中点的距离; LINE_DISMODE_CNTTOLINE, //中点到直线的距离 LINE_DISMODE_LINETOLINE //线到线的距离;暂不支持; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LM_LINEDET_PARA_S { [MarshalAs(UnmanagedType.Struct)] public LM_RECT_S stRoirectpara; [MarshalAs(UnmanagedType.Struct)] public LM_RECT_S stRoirect; //roi区域;内部实际使用; public LM_LINE_GRAYDIR_E eGrayDir; //边缘由浅及深;0.浅及深;1,由深浅; public LM_LINE_ORDER_E eLineOrder; //第一条边; public LM_LINE_DIRECTION_E eLineDirection; //线条方向; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LM_CALIB_RULT_S { public int iFlagSuccess; //是否标定成功 public float fConvertCoefficient; //标定结果 } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LM_DISCORRECT_PARA_S { public int iFlagEnable; //是否使能畸变矫正; public int iImgWidth; public int iImgHeight; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public double[] fCammatrix; //相机参数; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public double[] fNewcammatInv; //相机相关参数; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public double[] fDisK; //径向畸变参数; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public double[] fDisP; //切向畸变参数; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LM_INIT_PARA_S { public int iLineDetNum; //线数量; public int paraimgw; //参数设置对应的w;需要换算; public int paraimgh; //参数设置对应的h;需要换算; [MarshalAs(UnmanagedType.ByValArray, SizeConst = LM_LINE_NUM_MAX, ArraySubType = UnmanagedType.LPStruct)] public LM_LINEDET_PARA_S[] stLineDetPara; //线检测参数; public LM_LINEDIS_MODE_E eLineDisMode; //距离模式; } public struct LM_POINT_S { short px; short py; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LM_LINE_RULT_INFO_S { bool bIsValid; float fA; float fB; float fC; LM_POINT_S stDisPt; LM_POINT_S stStartPt; LM_POINT_S stEndPt; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LM_RULT_S { public int rultnum; //线条数; public float LinePixeldis1; //结果1,像素结果; public float LinePhysicaldis1; //结果1对应的物理结果; public float LinePixeldis2; //结果2,像素结果; public float LinePhysicaldis2; //结果2对应的物理结果; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.LPStruct)] LM_LINE_RULT_INFO_S[] LineInfoF; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.LPStruct)] LM_LINE_RULT_INFO_S[] LineInfoS; } private IntPtr _handle; private LM_RULT_S _result; private LM_CALIB_RULT_S _calibrationRes; private LM_DISCORRECT_PARA_S _distortionPara; public LM_DISCORRECT_PARA_S DistortionPara { get { return _distortionPara; } set { _distortionPara = value; } } private LM_INIT_PARA_S _lmInitPara; public LM_INIT_PARA_S LMInitPara { get { return _lmInitPara; } set { _lmInitPara = value; } } #endregion #region C++DLLToC#DLL [DllImport("LineMeasure.dll", EntryPoint = "?LM_LineMeasureInit@@YAPAXPAU_LM_INIT_PARA_S_@@H@Z", CallingConvention = CallingConvention.Cdecl)] //[DllImport("LineMeasure.dll")] //[DllImport("LineMeasure.dll", EntryPoint = "#5")] private static extern IntPtr LM_LineMeasureInit([In, Out] IntPtr stInitPara, int iDebugMode); [DllImport("LineMeasure.dll", EntryPoint = "?LM_LineMeasureProcess@@YAHPAXPAEHHPAU_LM_Rult_S_@@@Z", CallingConvention = CallingConvention.Cdecl)] //[DllImport("LineMeasure.dll")] private static extern int LM_LineMeasureProcess(IntPtr handle, [In, Out]byte[] grayimg, int imgw, int imgh, [In, Out]IntPtr lmrult); [DllImport("LineMeasure.dll", EntryPoint = "?LM_LineMeasureRelease@@YAXPAX@Z", CallingConvention = CallingConvention.Cdecl)] //[DllImport("LineMeasure.dll")] private static extern void LM_LineMeasureRelease(IntPtr handle); [DllImport("LineMeasure.dll", EntryPoint = "?LM_LineMeasureCalibration@@YAXPAEHHMPAU_LM_CALIB_RULT_S_@@@Z", CallingConvention = CallingConvention.Cdecl)] //[DllImport("LineMeasure.dll")] private static extern void LM_LineMeasureCalibration(IntPtr handle, [In, Out]byte[] grayimg, int imgw, int imgh, float rangedis, [In, Out]LM_CALIB_RULT_S calibrult); [DllImport("LineMeasure.dll", EntryPoint = "?LM_LineMeasureCalibSet@@YAXPAXPAU_LM_CALIB_RULT_S_@@@Z", CallingConvention = CallingConvention.Cdecl)] //[DllImport("LineMeasure.dll")] private static extern void LM_LineMeasureCalibSet(IntPtr handle, [In, Out]LM_CALIB_RULT_S calibrult); [DllImport("LineMeasure.dll", EntryPoint = "?LM_DistortionCalibSet@@YAXPAXPAU_LM_DISCORRECT_PARA_S_@@@Z", CallingConvention = CallingConvention.Cdecl)] //[DllImport("LineMeasure.dll")] private static extern void LM_DistortionCalibSet(IntPtr handle, [In, Out]LM_DISCORRECT_PARA_S discorrpara); [DllImport("LineMeasure.dll", EntryPoint = "?LM_LineMeasureReConfig@@YAXPEAXPEAU_LM_INIT_PARA_S_@@@Z", CallingConvention = CallingConvention.Cdecl)] //[DllImport("LineMeasure.dll")] private static extern void LM_LineMeasureReConfig(IntPtr handle, [In, Out]LM_INIT_PARA_S para); [DllImport("kernel32")] private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); [DllImport("kernel32")] private static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, [In, Out] char[] lpReturnedString, uint nSize, string lpFileName); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName); [DllImport("kernel32.dll")] public static extern Boolean AllocConsole(); [DllImport("kernel32.dll")] public static extern Boolean FreeConsole(); /// /// 控制台输出内容 /// /// 输入文本 /// 输出颜色 public static void WriteLine(string output, ConsoleColor color) { Console.ForegroundColor = color; Console.WriteLine(@"[{0}] {1}", DateTime.Now, output); } private string ReadString(string section, string key, string def, string fileName) { StringBuilder temp = new StringBuilder(1024); try { GetPrivateProfileString(section, key, def, temp, 1024, fileName); } catch { } return temp.ToString(); } private IntPtr ParaStructToPtr(LM_INIT_PARA_S para) { IntPtr pP1 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LM_INIT_PARA_S))); Marshal.WriteByte(pP1, 0); Marshal.StructureToPtr(para, pP1, true); return pP1; } IntPtr pP1; private IntPtr ResultToPtr(LM_RULT_S res) { pP1 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LM_RULT_S))); Marshal.WriteByte(pP1, 0); Marshal.StructureToPtr(res, pP1, true); return pP1; } private LM_RULT_S PtrToResult(IntPtr ptRes) { return (LM_RULT_S)Marshal.PtrToStructure(ptRes, typeof(LM_RULT_S)); } public int Init(LM_INIT_PARA_S para, int debug) { _handle = LM_LineMeasureInit(ParaStructToPtr(para), debug); return 0; } public void Calibration(byte[] grayimg, int width, int height, float rangedis) { LM_LineMeasureCalibration(_handle, grayimg, width, height, rangedis, _calibrationRes); } public void CaliSet() { LM_LineMeasureCalibSet(_handle, _calibrationRes); } //public void Cali public void DistortionCali() { } private IntPtr StructToPtr(Type tp, Object val) { IntPtr pP1 = Marshal.AllocHGlobal(Marshal.SizeOf(tp)); Marshal.WriteByte(pP1, 0); Marshal.StructureToPtr(val, pP1, true); return pP1; } #endregion } }