using HalconDotNet;
|
using LB_VisionControls;
|
using LB_VisionProcesses.Alogrithms.Halcon;
|
using System;
|
using System.Collections.Generic;
|
using System.Drawing.Imaging;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
|
namespace LB_VisionProcesses.Alogrithms.Halcon
|
{
|
public class HFindEllipseTool : TAlgorithm
|
{
|
public HFindEllipseTool()
|
{
|
strProcessClass = "LB_VisionProcesses.Alogrithms.Halcon.HFindEllipseTool";
|
strProcessName = "Halcon2D_找弧工具";
|
|
Params.Inputs.Add("卡尺数量", 6);
|
Params.Inputs.Add("卡尺长度", 30);
|
Params.Inputs.Add("卡尺宽度", 10);
|
Params.Inputs.Add("过滤一半像素", 2);
|
Params.Inputs.Add("对比度阈值", 5);
|
Params.Inputs.Add("极性", "Ignore");
|
Params.Inputs.Add("边缘位置", "Best");
|
Params.Inputs.Add("忽略点数", 0);
|
|
Params.Outputs.Add("X", new List<double>());
|
Params.Outputs.Add("Y", new List<double>());
|
Params.Outputs.Add("CenterX", 0.0);
|
Params.Outputs.Add("CenterY", 0.0);
|
Params.Outputs.Add("StartPhi", 0.0);
|
Params.Outputs.Add("StartAngle", 0.0);
|
Params.Outputs.Add("EndPhi", 0.0);
|
Params.Outputs.Add("EndAngle", 0.0);
|
Params.Outputs.Add("Phi", 0.0);
|
Params.Outputs.Add("Angle", 0.0);
|
Params.Outputs.Add("Count", 0);
|
Params.Outputs.Add("Radius", 0.0);
|
Params.Outputs.Add("Ellipse", new HEllipse());
|
|
Params.ROI = new HEllipse(0, 0, 0, 250, 250, 0, Math.PI);
|
}
|
|
/// <summary>
|
/// 算子逻辑
|
/// </summary>
|
public override void TAlgorithmMain()
|
{
|
#region 初始化变量
|
HObject ho_Regions, ho_EllipseXld;
|
HOperatorSet.GenEmptyObj(out ho_Regions);
|
HOperatorSet.GenEmptyObj(out ho_EllipseXld);
|
#endregion
|
|
try
|
{
|
if (InputImage == null)
|
{
|
Msg = "输入图片为空";
|
Result = false;
|
return;
|
}
|
//if (InputImage is Bitmap)
|
//{
|
// try
|
// {
|
// using (HImage hImage = new HImage())
|
// {
|
// Rectangle rect = new Rectangle(0, 0, ((Bitmap)InputImage).Width, ((Bitmap)InputImage).Height);
|
// BitmapData srcBmpData = ((Bitmap)InputImage).LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
|
// hImage.GenImageInterleaved(srcBmpData.Scan0, "rgbx", ((Bitmap)InputImage).Width, ((Bitmap)InputImage).Height, 0, "byte", ((Bitmap)InputImage).Width, ((Bitmap)InputImage).Height, 0, 0, -1, 0);
|
// ((Bitmap)InputImage).UnlockBits(srcBmpData);
|
// //((Bitmap)InputImage).Dispose();
|
// InputImage = null;
|
// InputImage = hImage.Clone();
|
// }
|
// }
|
// catch (Exception ex)
|
// {
|
// }
|
//}
|
if (!(InputImage is HObject))
|
{
|
Msg = "输入图片格式不为HObject";
|
Result = false;
|
return;
|
}
|
|
#region 裁剪区域
|
if (!(Params.ROI is HEllipse))
|
{
|
Msg = "ROI类型错误,必须为HEllipse类型";
|
Result = false;
|
return;
|
}
|
|
if (!(InputImage is HObject))
|
{
|
Msg = "输入图片类型错误,必须为HObject类型";
|
Result = false;
|
return;
|
}
|
|
HObject DomainImage = ((HObject)InputImage)?.CopyObj(1, -1);
|
#endregion
|
|
#region 算子逻辑
|
Record = new ObjectRecord();
|
HObject hoDomainImage = DomainImage as HObject;
|
HTuple hv_Channels = new HTuple();
|
//判断是否为灰度图
|
using (HDevDisposeHelper dh = new HDevDisposeHelper())
|
{
|
try
|
{
|
HOperatorSet.CountChannels(hoDomainImage, out hv_Channels);
|
if (hv_Channels.TupleInt() != 1)
|
HOperatorSet.Rgb1ToGray(hoDomainImage, out hoDomainImage);
|
|
//转换后再次检查是否为灰度图
|
HOperatorSet.CountChannels(hoDomainImage, out hv_Channels);
|
if (hv_Channels.TupleInt() != 1)
|
{
|
HOperatorSet.Rgb1ToGray(hoDomainImage, out hoDomainImage);
|
Msg = "输入图片不为灰度图";
|
Result = false;
|
return;
|
}
|
}
|
catch
|
{
|
Msg = "输入图片不为灰度图且转换失败";
|
Result = false;
|
return;
|
}
|
}
|
|
int hv_Elements = Convert.ToInt16(Params.Inputs["卡尺数量"]);
|
double hv_DetectHeight = Convert.ToDouble(Params.Inputs["卡尺长度"]);
|
double hv_DetectWidth = Convert.ToDouble(Params.Inputs["卡尺宽度"]);
|
int hv_Sigma = Convert.ToInt16(Params.Inputs["过滤一半像素"]);
|
int hv_Threshold = Convert.ToInt16(Params.Inputs["对比度阈值"]);
|
int hv_IgnoreNum = Convert.ToInt16(Params.Inputs["忽略点数"]);
|
|
Enum.TryParse(Params.Inputs["极性"]?.ToString(), out Transition transition);
|
string hv_Transition = "ignore";
|
switch (transition)
|
{
|
case Transition.Positive:
|
hv_Transition = "positive";
|
break;
|
case Transition.Negative:
|
hv_Transition = "negative";
|
break;
|
case Transition.Ignore:
|
default:
|
hv_Transition = "ignore";
|
break;
|
}
|
|
Enum.TryParse(Params.Inputs["边缘位置"]?.ToString(), out Selector selector);
|
string hv_Select = "best";
|
switch (selector)
|
{
|
case Selector.First:
|
hv_Select = "first";
|
break;
|
case Selector.Last:
|
hv_Select = "last";
|
break;
|
case Selector.Best:
|
default:
|
hv_Select = "best";
|
break;
|
}
|
|
double CenterRow = Convert.ToDouble(((HEllipse)Params.ROI).Y);
|
double CenterColumn = Convert.ToDouble(((HEllipse)Params.ROI).X);
|
double Radius1 = Convert.ToDouble(((HEllipse)Params.ROI).Radius1);
|
double Radius2 = Convert.ToDouble(((HEllipse)Params.ROI).Radius2);
|
double StartPhi = Convert.ToDouble(((HEllipse)Params.ROI).StartPhi);
|
double EndPhi = Convert.ToDouble(((HEllipse)Params.ROI).EndPhi);
|
|
RakeEllipse(hoDomainImage, out ho_Regions, hv_Elements, hv_DetectHeight, hv_DetectWidth
|
, hv_Sigma, hv_Threshold, hv_Transition, hv_Select
|
, CenterRow, CenterColumn, Radius1, Radius2, StartPhi, EndPhi
|
, out HTuple hv_ResultRow, out HTuple hv_ResultColumn);
|
|
#endregion
|
|
#region 结果处理
|
List<double> X = new List<double>();
|
List<double> Y = new List<double>();
|
double CenterX = 0;
|
double CenterY = 0;
|
double Radius = 0;
|
double Phi = 0;
|
HEllipse HEllipse = new HEllipse();
|
if (hv_ResultRow.Type != HTupleType.EMPTY && hv_ResultRow.Length > 0)
|
{
|
for (int k = 0; k < hv_ResultRow.Length; k++)
|
{
|
Y.Add(hv_ResultRow[k].D);
|
X.Add(hv_ResultColumn[k].D);
|
}
|
|
if (X.Count >= 3)
|
{
|
pts_to_best_circle(out ho_EllipseXld, hv_ResultRow, hv_ResultColumn, hv_IgnoreNum
|
, out HTuple hv_CenterRow, out HTuple hv_CenterColumn, out HTuple hv_Radius,
|
out HTuple hv_StartPhi, out HTuple hv_EndPhi, out HTuple hv_PointOrder, out HTuple hv_FitError);
|
((ObjectRecord)Record).AddXld(ho_EllipseXld);
|
CenterX = hv_CenterColumn.D;
|
CenterY = hv_CenterRow.D;
|
StartPhi = hv_StartPhi.D;
|
EndPhi = hv_EndPhi.D;
|
Radius = hv_Radius.D;
|
//计算直线与x轴的夹角,逆时针方向为正向
|
HOperatorSet.AngleLx(Y[0], X[0], Y[Y.Count - 1], X[Y.Count - 1], out HTuple hv_ATan);
|
Phi = hv_ATan;
|
|
HEllipse = new HEllipse(CenterX, CenterY, Phi, Radius, Radius, StartPhi, EndPhi);
|
}
|
else
|
{
|
Msg = "找弧失败";
|
Result = false;
|
return;
|
}
|
}
|
else
|
{
|
Msg = "找弧失败";
|
Result = false;
|
return;
|
}
|
Params.Outputs["X"] = X;
|
Params.Outputs["Y"] = Y;
|
Params.Outputs.Add("CenterX", CenterX);
|
Params.Outputs.Add("CenterY", CenterY);
|
Params.Outputs.Add("StartPhi", StartPhi);
|
Params.Outputs.Add("StartAngle", StartPhi * 180.0 / Math.PI);
|
Params.Outputs.Add("EndPhi", EndPhi);
|
Params.Outputs.Add("EndAngle", EndPhi * 180.0 / Math.PI);
|
Params.Outputs.Add("Phi", Phi);
|
Params.Outputs.Add("Angle", Phi * 180.0 / Math.PI);
|
Params.Outputs.Add("Count", X.Count);
|
Params.Outputs.Add("Radius", Radius);
|
Params.Outputs["Ellipse"] = HEllipse;
|
#endregion
|
|
#region 生成OutputImage给后续处理
|
try
|
{
|
OutputImage = hoDomainImage;
|
}
|
catch (Exception ex)
|
{
|
Msg = "生成OutputImage失败,原因是:" + ex.ToString();
|
Result = false;
|
return;
|
}
|
#endregion
|
|
if (Msg == "运行超时")
|
{
|
Result = false;
|
return;
|
}
|
|
Msg = "运行成功";
|
Result = true;
|
return;
|
}
|
catch (Exception ex)
|
{
|
Msg = "运行失败,原因是:" + ex.ToString().TrimEnd();
|
OutputImage = null;
|
Result = false;
|
return;
|
}
|
finally
|
{
|
if (!Result)
|
{
|
Params.Outputs.Add("X", new List<double>());
|
Params.Outputs.Add("Y", new List<double>());
|
Params.Outputs.Add("CenterX", 0.0);
|
Params.Outputs.Add("CenterY", 0.0);
|
Params.Outputs.Add("StartPhi", 0.0);
|
Params.Outputs.Add("StartAngle", 0.0);
|
Params.Outputs.Add("EndPhi", 0.0);
|
Params.Outputs.Add("EndAngle", 0.0);
|
Params.Outputs.Add("Phi", 0.0);
|
Params.Outputs.Add("Angle", 0.0);
|
Params.Outputs.Add("Count", 0);
|
Params.Outputs.Add("Radius", 0.0);
|
Params.Outputs.Add("Ellipse", new HEllipse());
|
}
|
|
bCompleted = true;
|
#region 内存释放
|
ho_Regions.Dispose();
|
#endregion
|
}
|
}
|
}
|
}
|