using HalconDotNet; using LB_VisionControl; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LB_VisionProcesses.Alogrithms.Halcon { public class HCaltab : IDisposable { public HCaltab() { } public HCaltab(HCaltab HCaltab) { CameraInner = HCaltab.CameraInner.Clone(); CameraPose = HCaltab.CameraPose.Clone(); CameraInner_Adaptive = HCaltab.CameraInner_Adaptive.Clone(); Map = HCaltab.Map.Clone(); Xld = HCaltab.Xld.Clone(); CaltbImages = new List(HCaltab.CaltbImages); Params.XNum = HCaltab.Params.XNum; Params.YNum = HCaltab.Params.YNum; Params.MarkDist = HCaltab.Params.MarkDist; Params.DiameterRatio = HCaltab.Params.DiameterRatio; Params.Focus = HCaltab.Params.Focus; Params.Kappa = HCaltab.Params.Kappa; Params.Sx = HCaltab.Params.Sx; Params.Sy = HCaltab.Params.Sy; Params.Width = HCaltab.Params.Width; Params.Height = HCaltab.Params.Height; } public void Dispose() { try { ClearCaltbImages(); if (Map != null && Map.IsInitialized()) Map.Dispose(); if (Xld != null && Xld.IsInitialized()) Xld.Dispose(); } catch { } } /// /// 名称 /// public string Name = "Calibration_0"; /// /// 信息 /// public string Msg = ""; /// /// 结果 /// public bool Result { get { if (Map == null || !Map.IsInitialized()) return false; if (CameraInner_Adaptive == null || CameraInner_Adaptive.Length == 0 || CameraPose == null || CameraPose.Length == 0) return false; return false; } } /// /// 文件路径 /// public string FilePath = $"C://Name//"; /// /// 标定参数文件 /// public HCalibrationParam Params = new HCalibrationParam(); List CaltbImages = new List(); public HObject Image { get { if (CaltbImages.Count > 0) return CaltbImages[0]; else return null; } } public HObject Xld = new HObject(); /// /// 相机内参 /// HTuple CameraInner = new HTuple(); /// /// 相机外参 /// HTuple CameraPose = new HTuple(); /// /// 无畸变的相机内参 /// HTuple CameraInner_Adaptive = new HTuple(); /// /// 畸变变换图 /// HObject Map = new HObject(); #region 矫正结果 public bool GetCaltbImage(HObject OriImage, out HObject CaltbImage) { CaltbImage = OriImage; try { if (OriImage == null || !OriImage.IsInitialized() || Map == null || !Map.IsInitialized()) return false; HOperatorSet.MapImage(OriImage, Map, out CaltbImage); return true; } catch { return false; } } public bool GetCaltbPoint(HPoint OriPoint, out HPoint CaltbPoint) { CaltbPoint = new HPoint(OriPoint); try { if (CameraInner_Adaptive == null || CameraInner_Adaptive.Length == 0 || CameraPose == null || CameraPose.Length == 0) return false; HOperatorSet.ImagePointsToWorldPlane(CameraInner_Adaptive, CameraPose , OriPoint.Row, OriPoint.Column, "mm", out HTuple row, out HTuple col); if (row.Length == 0 || col.Length == 0) return false; CaltbPoint.Row = row.D; CaltbPoint.Column = col.D; return true; } catch { return false; } } #endregion public bool LoadCaltbImages() { try { ClearCaltbImages(); for (int i = 0; i < 999; i++) { string ImagePath = FilePath + $"//CaltbImages_{i}.bmp"; if (!File.Exists(ImagePath)) break; HOperatorSet.ReadImage(out HObject ho_Image, ImagePath); } return true; } catch { return false; } } public bool SaveCaltbImages() { //判断文件夹是否存在,防呆输入为文件名称 if (!Directory.Exists(FilePath)) { try { Directory.CreateDirectory(FilePath); } catch { } } try { for (int i = 0; i <= CaltbImages.Count; i++) { string ImagePath = FilePath + $"//CaltbImages_{i}.bmp"; var Image = CaltbImages[i]; if (Image != null && Image.IsInitialized()) { HOperatorSet.CountChannels(Image, out HTuple hv_Channels); if (hv_Channels.TupleInt() != 1) HOperatorSet.Rgb1ToGray(Image, out Image); //Halcon存图需要用斜杠 ImagePath.Replace("\\", "/"); HOperatorSet.WriteImage(Image, "bmp", 0, ImagePath); } } } catch { return false; } return true; } public void ClearCaltbImages() { foreach (var image in CaltbImages) { if (image != null && image.IsInitialized()) image.Dispose(); } CaltbImages.Clear(); CaltbImages = new List(); } public bool CheckCaltbImage(List lst_Images = null, int Width = 0, int Height = 0) { if (lst_Images == null) lst_Images = CaltbImages; if (Width == 0 || Height == 0) { Width = Params.Width; Height = Params.Height; } foreach (var imge in lst_Images) { if (imge == null || !imge.IsInitialized()) return false; HOperatorSet.GetImageSize(imge, out HTuple hv_Width, out HTuple hv_Height); if (hv_Width.Length == 0 || hv_Height.Length == 0 || hv_Width.I != Width || hv_Height.I != Height) return false; } return true; } public bool Caltb(List lst_Images) { try { if (!CheckCaltbImage(lst_Images)) return false; BaseCalib.CreateCaltab(FilePath, Params.XNum, Params.YNum, Params.MarkDist, Params.DiameterRatio); BaseCalib.gen_cam_par_area_scan_division(Params.Focus / 1000.0, Params.Kappa , Params.Sx / 1000000.0, Params.Sy / 1000000.0 , Params.Width / 2.0, Params.Height / 2.0, Params.Width, Params.Height, out HTuple CameraParam); string CalPlateDescr = Params.CalPlateDescr; string CameraInnerPath = FilePath + "//CameraInner_Adaptive.tup"; string CameraPosePath = FilePath + "//CameraPose.tup"; CalPlateDescr.Replace("\\", "/"); CameraInnerPath.Replace("\\", "/"); CameraPosePath.Replace("\\", "/"); BaseCalib.CaltabCalib(CameraParam, lst_Images , out HTuple hv_CameraInner, out HTuple hv_CameraPose, out HTuple hv_CameraInner_Adaptive , out HObject ho_Map, out Xld , CalPlateDescr, CameraInnerPath, CameraPosePath); if (hv_CameraInner == null || hv_CameraPose == null || hv_CameraInner_Adaptive == null || ho_Map == null || !ho_Map.IsInitialized()) return false; CameraInner = hv_CameraInner.Clone(); CameraPose = hv_CameraPose.Clone(); CameraInner_Adaptive = hv_CameraInner_Adaptive.Clone(); Map = ho_Map.Clone(); CaltbImages = lst_Images; return SaveCaltbImages(); } catch { return false; } } public bool Caltb(List lst_Images, int XNum, int YNum, int MarkDist, double DiameterRatio , int Focus, int Kappa, double Sx, double Sy, int Width, int Height) { if (!CheckCaltbImage(lst_Images, Width, Height)) return false; BaseCalib.CreateCaltab(FilePath, XNum, YNum, MarkDist, DiameterRatio); BaseCalib.gen_cam_par_area_scan_division(Focus / 1000.0, Kappa , Sx / 1000000.0, Sy / 1000000.0 , Width / 2.0, Height / 2.0, Width, Height, out HTuple CameraParam); string CalPlateDescr = Params.CalPlateDescr; string CameraInnerPath = FilePath + "//CameraInner_Adaptive.tup"; string CameraPosePath = FilePath + "//CameraPose.tup"; CalPlateDescr.Replace("\\", "/"); CameraInnerPath.Replace("\\", "/"); CameraPosePath.Replace("\\", "/"); BaseCalib.CaltabCalib(CameraParam, CaltbImages , out HTuple hv_CameraInner, out HTuple hv_CameraPose, out HTuple hv_CameraInner_Adaptive , out HObject ho_Map, out Xld , CalPlateDescr, CameraInnerPath, CameraPosePath); if (hv_CameraInner == null || hv_CameraPose == null || hv_CameraInner_Adaptive == null || ho_Map == null || !ho_Map.IsInitialized()) return false; CameraInner = hv_CameraInner.Clone(); CameraPose = hv_CameraPose.Clone(); CameraInner_Adaptive = hv_CameraInner_Adaptive.Clone(); Map = ho_Map.Clone(); CaltbImages = lst_Images; Params.XNum = XNum; Params.YNum = YNum; Params.MarkDist = MarkDist; Params.DiameterRatio = DiameterRatio; Params.Focus = Focus; Params.Kappa = Kappa; Params.Sx = Sx; Params.Sy = Sy; Params.Width = Width; Params.Height = Height; return SaveCaltbImages(); } public bool Load(string fullPath) { try { // 获取不带文件名的目录路径 Name = Path.GetFileNameWithoutExtension(fullPath); // 修正真实路径,工具其路径为一个文件夹,而不是一个文件 FilePath = Path.GetDirectoryName(fullPath) + Name; if (!File.Exists(fullPath)) { Debug.WriteLine("文件不存在创建空文件"); Save(FilePath); return true; } string strJson = string.Empty; using (StreamReader streamReader = new StreamReader(fullPath, Encoding.UTF8)) { strJson = streamReader.ReadToEnd(); streamReader.Close(); } Params = JsonConvert.DeserializeObject(strJson); if (Params == null) return false; Params.Name = Name; Params.FilePath = FilePath; string CalPlateDescr = Params.CalPlateDescr; string CameraInnerPath = FilePath + "//CameraInner_Adaptive.tup"; string CameraPosePath = FilePath + "//CameraPose.tup"; //相机内参 HOperatorSet.ReadTuple(CameraInnerPath, out CameraInner_Adaptive); //相机外参 HOperatorSet.ReadTuple(CameraPosePath, out CameraPose); //BaseCalib.CreateCaltab(FilePath, Params.XNum, Params.YNum, Params.MarkDist, Params.DiameterRatio); //BaseCalib.gen_cam_par_area_scan_division(Params.Focus / 1000.0, Params.Kappa // , Params.Sx / 1000000.0, Params.Sy / 1000000.0 // , Params.Width / 2.0, Params.Height / 2.0, Params.Width, Params.Height, out HTuple CameraParam); //CalPlateDescr.Replace("\\", "/"); //CameraInnerPath.Replace("\\", "/"); //CameraPosePath.Replace("\\", "/"); //BaseCalib.CaltabCalib(CameraParam, CaltbImages // , out CameraInner, out CameraPose, out CameraInner_Adaptive, out Map, out _ // , CalPlateDescr, CameraInnerPath, CameraPosePath); return LoadCaltbImages(); } catch { return false; } } public bool Save(string filePath) { try { if (string.IsNullOrEmpty(filePath) || filePath.Trim() == "") { Debug.WriteLine("文件路径不完整"); return false; } // 修正真实路径,工具其路径为一个文件夹,而不是一个文件 filePath += ("//" + Name); string strJson = string.Empty; var settings = new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented, // 自定义缩进(4空格) ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() } }; strJson = JsonConvert.SerializeObject(Params, settings); Params = JsonConvert.DeserializeObject(strJson); //判断文件夹是否存在,防呆输入为文件名称 if (!Directory.Exists(filePath)) { try { Directory.CreateDirectory(filePath); } catch (Exception) { } } // filePath 已经含了Name File.WriteAllText(filePath + "//Params.json", strJson, Encoding.UTF8); // filePath 已经含了Name FilePath = filePath; try { string CameraInnerPath = FilePath + "//CameraInner_Adaptive.tup"; string CameraPosePath = FilePath + "//CameraPose.tup"; //相机内参 HOperatorSet.WriteTuple(CameraInner_Adaptive, CameraInnerPath); //相机外参 HOperatorSet.WriteTuple(CameraPose, CameraPosePath); } catch { } return SaveCaltbImages(); } catch { return false; } } } /// /// 畸变标定参数类 /// [Serializable] public class HCalibrationParam { public HCalibrationParam() { } /// /// 名称 /// public string Name = "Params"; /// /// 文件路径 /// public string FilePath = @"C://"; /// /// 圆点行数 /// public int XNum { get; set; } = 7; /// /// 圆点行数 /// public int YNum { get; set; } = 7; /// /// 两个圆之间的距离, 单位mm /// public double MarkDist { get; set; } = 1.25; /// /// 比例值, Mark直径比上Mark中心距离 /// public double DiameterRatio { get; set; } = 0.5; /// /// 用于标定的描述文件 /// public string CalPlateDescr { get { return FilePath + $"//Caltab_{XNum}*{YNum}_{DiameterRatio}.descr"; } } /// /// 制作标定板的PS文件 /// public string CalPlatePSFile { get { return FilePath + $"//Caltab_{XNum}*{YNum}_{DiameterRatio}.ps"; } } /// /// 厚度 /// public int Thickness { get; set; } = 1; /// /// 相机类型(面扫描(除法)) /// public string CamType { get; set; } = "area_scan_division"; /// /// 单个相机像元的宽 /// public double Sx { get; set; } = 8.3; /// /// 单个相机像元的高 /// public double Sy { get; set; } = 8.3; /// /// 图像宽 /// public int Width { get; set; } = 1120; /// /// 图像高 /// public int Height { get; set; } = 1120; /// /// 镜头的焦距 /// public double Focus { get; set; } = 8; public double Kappa { get; set; } = 0; /// /// 标定效果, 越接近0越越好 /// public double RMS { get; set; } = 999.9; } }