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<HObject>(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 { }
|
}
|
|
/// <summary>
|
/// 名称
|
/// </summary>
|
public string Name = "Calibration_0";
|
|
/// <summary>
|
/// 信息
|
/// </summary>
|
public string Msg = "";
|
|
/// <summary>
|
/// 结果
|
/// </summary>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// 文件路径
|
/// </summary>
|
public string FilePath = $"C://Name//";
|
|
/// <summary>
|
/// 标定参数文件
|
/// </summary>
|
public HCalibrationParam Params = new HCalibrationParam();
|
|
List<HObject> CaltbImages = new List<HObject>();
|
|
public HObject Image
|
{
|
get
|
{
|
if (CaltbImages.Count > 0)
|
return CaltbImages[0];
|
else
|
return null;
|
}
|
}
|
|
public HObject Xld = new HObject();
|
|
/// <summary>
|
/// 相机内参
|
/// </summary>
|
HTuple CameraInner = new HTuple();
|
|
/// <summary>
|
/// 相机外参
|
/// </summary>
|
HTuple CameraPose = new HTuple();
|
|
/// <summary>
|
/// 无畸变的相机内参
|
/// </summary>
|
HTuple CameraInner_Adaptive = new HTuple();
|
|
/// <summary>
|
/// 畸变变换图
|
/// </summary>
|
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<HObject>();
|
}
|
|
public bool CheckCaltbImage(List<HObject> 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<HObject> 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<HObject> 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<HCalibrationParam>(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<HCalibrationParam>(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; }
|
}
|
}
|
|
/// <summary>
|
/// 畸变标定参数类
|
/// </summary>
|
[Serializable]
|
public class HCalibrationParam
|
{
|
public HCalibrationParam() { }
|
|
/// <summary>
|
/// 名称
|
/// </summary>
|
public string Name = "Params";
|
|
/// <summary>
|
/// 文件路径
|
/// </summary>
|
public string FilePath = @"C://";
|
|
/// <summary>
|
/// 圆点行数
|
/// </summary>
|
public int XNum { get; set; } = 7;
|
|
/// <summary>
|
/// 圆点行数
|
/// </summary>
|
public int YNum { get; set; } = 7;
|
|
/// <summary>
|
/// 两个圆之间的距离, 单位mm
|
/// </summary>
|
public double MarkDist { get; set; } = 1.25;
|
|
/// <summary>
|
/// 比例值, Mark直径比上Mark中心距离
|
/// </summary>
|
public double DiameterRatio { get; set; } = 0.5;
|
|
/// <summary>
|
/// 用于标定的描述文件
|
/// </summary>
|
public string CalPlateDescr { get { return FilePath + $"//Caltab_{XNum}*{YNum}_{DiameterRatio}.descr"; } }
|
|
/// <summary>
|
/// 制作标定板的PS文件
|
/// </summary>
|
public string CalPlatePSFile { get { return FilePath + $"//Caltab_{XNum}*{YNum}_{DiameterRatio}.ps"; } }
|
|
/// <summary>
|
/// 厚度
|
/// </summary>
|
public int Thickness { get; set; } = 1;
|
|
/// <summary>
|
/// 相机类型(面扫描(除法))
|
/// </summary>
|
public string CamType { get; set; } = "area_scan_division";
|
|
/// <summary>
|
/// 单个相机像元的宽
|
/// </summary>
|
public double Sx { get; set; } = 8.3;
|
|
/// <summary>
|
/// 单个相机像元的高
|
/// </summary>
|
public double Sy { get; set; } = 8.3;
|
|
/// <summary>
|
/// 图像宽
|
/// </summary>
|
public int Width { get; set; } = 1120;
|
|
/// <summary>
|
/// 图像高
|
/// </summary>
|
public int Height { get; set; } = 1120;
|
|
/// <summary>
|
/// 镜头的焦距
|
/// </summary>
|
public double Focus { get; set; } = 8;
|
|
public double Kappa { get; set; } = 0;
|
|
/// <summary>
|
/// 标定效果, 越接近0越越好
|
/// </summary>
|
public double RMS { get; set; } = 999.9;
|
}
|
}
|