using HalconDotNet;
using LB_VisionControl;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Threading.Tasks;
namespace LB_VisionProcesses.Alogrithms.Halcon
{
public class BaseCalib
{
#region 标定板
// Procedures
// Chapter: Calibration / Camera Parameters
// Short Description: Generate a camera parameter tuple for an area scan camera with distortions modeled by the division model.
///
/// 面阵相机内参生成
///
///
///
///
///
///
///
///
///
///
public static void gen_cam_par_area_scan_division(HTuple hv_Focus, HTuple hv_Kappa, HTuple hv_Sx,
HTuple hv_Sy, HTuple hv_Cx, HTuple hv_Cy, HTuple hv_ImageWidth, HTuple hv_ImageHeight,
out HTuple hv_CameraParam)
{
// Local iconic variables
// Initialize local and output iconic variables
hv_CameraParam = new HTuple();
//Generate a camera parameter tuple for an area scan camera
//with distortions modeled by the division model.
//
hv_CameraParam.Dispose();
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
hv_CameraParam = new HTuple();
hv_CameraParam[0] = "area_scan_division";
hv_CameraParam = hv_CameraParam.TupleConcat(hv_Focus, hv_Kappa, hv_Sx, hv_Sy, hv_Cx, hv_Cy, hv_ImageWidth, hv_ImageHeight);
}
return;
}
///
/// 生成棋盘格标定板文件
///
///
///
///
public static void CreateCaltab(string dirPath = @"C://", int XNum = 7, int YNum = 7
, double MarkDist = 1.25, double DiameterRatio = 0.5)
{
try
{
//XNum:每行黑色标志圆点的数量。
//YNum:每行黑色标志圆点的数量。
//MarkDist:两个就近黑色圆点中心之间的距离。
//DiameterRstio:黑色圆点半径与圆点中心距离的比值。
//CalPlateDescr:标定板描述文件的文件路径(.descr文件为标定板描述文件)。
//CalPlatePSFile:标定板图像文件的文件路径(.ps文件为标定板图形文件,可利用PS类软件打开)。
string CalPlateDescr = dirPath + $"Caltab_{XNum}*{YNum}_{DiameterRatio}.descr";
string CalPlatePSFile = dirPath + $"Caltab_{XNum}*{YNum}_{DiameterRatio}.ps";
HOperatorSet.GenCaltab(XNum, YNum, MarkDist / 1000.0, DiameterRatio, CalPlateDescr, CalPlatePSFile);
}
catch { }
}
public static void CaltabCalib(HTuple hv_CameraParam, List lst_Images
, out HTuple CameraInner, out HTuple CameraPose, out HTuple CameraInner_Adaptive
, out HObject Map, out HObject CircleXld
, string CalPlateDescr = "C:/Caltab.descr"
, string CameraInnerPath = "C:/CameraInner_Adaptive.tup", string CameraPosePath = "C:/CameraPose.tup")
{
CameraInner = null; CameraPose = null; CameraInner_Adaptive = null; Map = null; CircleXld = null;
try
{
//1.获取相机参数
//using (HDevDisposeHelper dh = new HDevDisposeHelper())
//{
// hv_CameraParam.Dispose();
// gen_cam_par_area_scan_division(0.008, 0, 5.2e-06, 5.2e-06, 3072 / 2, 2048 / 2, 3072,
// 2048, out hv_CameraParam);
//}
//2.创建标定对象
HOperatorSet.CreateCalibData("calibration_object", 1, 1, out HTuple hv_CalibDataID);
//3.在标定对象中设置相机参数
HOperatorSet.SetCalibDataCamParam(hv_CalibDataID, 0, new HTuple(), hv_CameraParam);
//4.在标定对象中设置标定板描述文件
HOperatorSet.SetCalibDataCalibObject(hv_CalibDataID, 0, CalPlateDescr);
//5.加载标定图像,进行标定
//- 标定板不要过曝,不要出现255的灰度值
//- 光照要均匀
//- 标定板特征点的对比度要高,黑白区域灰度值差100以上
//- 标定板在图像中至少占1 / 4面积
//- 特征点应该对焦清晰
//- 所有特征点应该全部落在图像范围内
//- 标定图像至少10幅
//- 标定板应该覆盖整个视野的各个角落
//- 标定板角度变化要明显
//- 图像大小要一致
int Index = 0;
if (lst_Images == null || lst_Images.Count == 0)
throw new Exception();
// 标定图片必须为黑白
try
{
for (int i = 0; i <= lst_Images.Count; i++)
{
var ho_Image = lst_Images[i];
HOperatorSet.CountChannels(ho_Image, out HTuple hv_Channels);
if (hv_Channels.TupleInt() != 1)
HOperatorSet.Rgb1ToGray(ho_Image, out ho_Image);
lst_Images[i] = ho_Image;
}
}
catch { }
foreach (var ho_Image in lst_Images)
{
//标定图像
HOperatorSet.FindCalibObject(ho_Image, hv_CalibDataID, 0, 0, Index, new HTuple(),
new HTuple());
//获取轮廓
HOperatorSet.GetCalibDataObservContours(out HObject ho_Contours, hv_CalibDataID, "marks", 0, 0, Index);
//获取圆心点和位姿
HOperatorSet.GetCalibDataObservPoints(hv_CalibDataID, 0, 0, Index
, out HTuple hv_Row, out HTuple hv_Column, out HTuple _, out HTuple _);
HOperatorSet.GenCrossContourXld(out CircleXld, hv_Row, hv_Column, 10, 0.785398);
}
//6.标定
HOperatorSet.CalibrateCameras(hv_CalibDataID, out HTuple hv_Error);
//7.获取相机内参
HOperatorSet.GetCalibData(hv_CalibDataID, "camera", 0, "params", out CameraInner);
//8.获取相机外参
HOperatorSet.GetCalibData(hv_CalibDataID, "calib_obj_pose", (new HTuple(0)).TupleConcat(
0), "pose", out HTuple hv_Pose);
HOperatorSet.SetOriginPose(hv_Pose, 0, 0, 0.002, out CameraPose);
//9.获取畸变参数
//描述:根据指定的径向畸变系数,求取理想无畸变的相机内参。
//参数:
//Mode:畸变模式
//CamParamIn:畸变的相机内部参数
//DistortionCoeffs :畸变系数值
//CamParamOut:已校正的相机内参
HOperatorSet.ChangeRadialDistortionCamPar("adaptive", CameraInner, 0, out CameraInner_Adaptive);
//10.保存相机参数
//相机内参
HOperatorSet.WriteTuple(CameraInner_Adaptive, CameraInnerPath);
//相机外参
HOperatorSet.WriteTuple(CameraPose, CameraPosePath);
//11.生成畸变矫正Map
//描述:根据指定图像和指定相加参数来矫正输入图像的畸变。change_radial_distortion_image根据摄像机内部参数CamParamIn和CamParamOut对输入图像图像的径向畸变进行改变。使用CamParamOut将位于区域区域内的输出图像的每个像素转换为图像平面,然后使用CamParamIn将其投影为图像的亚像素。通过双线性插值确定得到的灰度值。如果该亚像素在图像之外,则将图像重建中的对应像素设置为“黑色”并从图像域中消除。
//参数:
//Image:输入图像
//Region :矫正图像的区域
//ImageRectified :矫正图像
//CamParamIn:输入相机参数
//CamParamOut :输出相机参数
HOperatorSet.GenRadialDistortionMap(out Map, CameraInner, CameraInner_Adaptive, "bilinear");
}
catch { CameraInner = null; CameraPose = null; CameraInner_Adaptive = null; Map = null; CircleXld = null; }
}
public static void ApplyCaltabCalib(HObject Image, HObject Map, out HObject MappedImage)
{
try
{
HOperatorSet.MapImage(Image, Map, out MappedImage);
}
catch { MappedImage = null; }
}
public static void ApplyCaltabCalibByPoint(HPoint imagePoint, out HPoint worldPoint, HTuple hv_CaltabCalibParams, HTuple hv_PoseCalibParams)
{
worldPoint = new HPoint(imagePoint);
try
{
HOperatorSet.ImagePointsToWorldPlane(hv_CaltabCalibParams, hv_PoseCalibParams
, imagePoint.Row, imagePoint.Column, "mm", out HTuple Row, out HTuple Column);
worldPoint.Row = Row.D;
worldPoint.Column = Column.D;
}
catch { }
}
#endregion
#region 棋盘格
///
/// 生成棋盘格标定板文件
///
///
///
///
public static void CreateCheckerBoard(string dirPath = "C:\\", int size = 17, int count = 17)
{
try
{
string saveFullPath = dirPath + $"Grid_{size}*{size}_{count}.ps";
HOperatorSet.CreateRectificationGrid(size / 100.0, count, saveFullPath);
}
catch { }
}
public static void CheckerBoardCalib(HObject Image, out HObject Map
, int MinContrast = 25, int Radius = 10, int SigmaSaddlePoints = 2, int Threshold = 3
, double SigmaConnectGridPoints = 0.9, int MaxDist = 5, int GridSpacing = 45)
{
try
{
HOperatorSet.Rgb1ToGray(Image, out Image);
//****************************标定矫正过程**************************************
//查找结构化网格
//MinContrast 查找网格对比度
//Radius 查找网格半径
HOperatorSet.FindRectificationGrid(Image, out HObject ho_GridRegion, MinContrast, Radius);
HOperatorSet.ReduceDomain(Image, ho_GridRegion, out HObject Image_Reduced);
//提取(鞍)点,输出Row, Col
//'facet':滤波器
//Sigma:平滑系数
//Threshold:分割阈值
HOperatorSet.SaddlePointsSubPix(Image_Reduced, "facet", SigmaSaddlePoints, Threshold, out HTuple hv_Row, out HTuple hv_Col);
HOperatorSet.GenCrossContourXld(out HObject ho_SaddlePoints, hv_Row, hv_Col, 20, 1);
HOperatorSet.ConnectGridPoints(Image_Reduced, out HObject ho_ConnectingLines, hv_Row,
hv_Col, SigmaConnectGridPoints, MaxDist);
//生成变换图
HOperatorSet.GenGridRectificationMap(Image_Reduced, ho_ConnectingLines, out Map,
out HObject ho_Meshes, GridSpacing, 0, hv_Row, hv_Col, "bilinear");
}
catch { Map = null; }
}
public static void ApplyCheckerBoardCalibMap(HObject Image, HObject Map, out HObject MappedImage)
{
try
{
HOperatorSet.MapImage(Image, Map, out MappedImage);
}
catch { MappedImage = null; }
}
#endregion
}
}