爱炸薯条的小朋友

爱炸薯条的小朋友

1.前言

1.1什么是圆倒角

圆角是用一段与角的两边相切的圆弧替换原来的角,圆角的大小用圆弧的半径表示。

1.2代码实现方式

针对圆角的特性,由2条直线构成的圆弧,所以圆弧上位于2相交直线的中间。所以先获得2条直线的坐标,获取到2条直线的交点,然后再绘制2条线段的内接圆,然后以交点为起始点,内切圆圆心为终点,做一条线段,在做线段的垂线,相切于圆角,以垂线做为起始点,内切圆圆心作为终点,做N条采样直线,将获取到的采样点拟合成圆即可。
Halcon测量专栏-圆倒角-LMLPHP

2.程序

2.1C#和halcon程序

 #region // 计算圆倒角(1:计算2条直线的相切圆,2:求得直线交点到相切圆中心的角度,3:通过角度找出边缘拟合直线,并拟合边缘)
 public static bool RoundChamferR(HObject Image, bool FastSet, 
     HTuple BeginRow1, HTuple BeginCloumn1, HTuple EndRow1,HTuple EndCloumn1, 
     HTuple BeginRow2, HTuple BeginCloumn2, HTuple EndRow2,HTuple EndCloumn2,
     out HObject LineContours, out HTuple ResultRowBegin, out HTuple ResultColumnBegin, out HTuple ResultRowEnd, 
     out HTuple ResultCloumnEnd,
     out HObject LineContours2, out HTuple ResultRowBegin2, out HTuple ResultColumnBegin2, out HTuple ResultRowEnd2, 
     out HTuple ResultCloumnEnd2,
     out double R,out HObject Circle)
 {
     HOperatorSet.GenEmptyObj(out LineContours);
     HOperatorSet.GenEmptyObj(out LineContours2); 
     HOperatorSet.GenEmptyObj(out Circle);
     ResultRowBegin = -1;
     ResultRowEnd = -1;
     ResultColumnBegin = -1;
     ResultCloumnEnd = -1;
     ResultRowBegin2 = -1;
     ResultRowEnd2 = -1;
     ResultColumnBegin2 = -1;
     ResultCloumnEnd2 = -1;
     R = -1;

     try
     {
        
         bool line1 = false, line2 = false;
         if (FastSet)
         {
             line1 = Module.LineMeasure_(Image, BeginRow1, BeginCloumn1, EndRow1,  EndCloumn1, 10, 2, 1, 80, "uniform", "first", out LineContours,
                     out ResultRowBegin, out ResultColumnBegin, out ResultRowEnd,  out ResultCloumnEnd);
             line2 = Module.LineMeasure_(Image, BeginRow2, BeginCloumn2, EndRow2,  EndCloumn2, 10, 2, 1, 80, "uniform", "first", out LineContours2,
                     out ResultRowBegin2, out ResultColumnBegin2, out ResultRowEnd2,  out ResultCloumnEnd2);
         }
         if (!line1 || !line2)
         {
             return false;
         }
         
         HOperatorSet.IntersectionLines(BeginRow1, BeginCloumn1, EndRow1, EndCloumn1, BeginRow2, BeginCloumn2, EndRow2, EndCloumn2,
                     out HTuple row, out HTuple column, out HTuple isOverlapping);
         HOperatorSet.LineOrientation( ResultRowBegin,  ResultColumnBegin,  ResultRowEnd,  ResultCloumnEnd, out HTuple phi1);
         HOperatorSet.LineOrientation(ResultRowBegin2,  ResultColumnBegin2,  ResultRowEnd2,  ResultCloumnEnd2, out HTuple phi2);


         double midX = (ResultColumnBegin + ResultColumnBegin2) / 2;
         double midY = (ResultRowBegin + ResultRowBegin2) / 2;
         // 计算两条直线的垂直平分线的斜率
         double perpendicularSlope = -1 / ((phi1 + phi2) / 2);

         // 计算垂直平分线的截距
         double intercept = midY - perpendicularSlope * midX;

         // 计算圆心坐标
         double circleCenterX = -perpendicularSlope * intercept / (perpendicularSlope * perpendicularSlope + 1);
         double circleCenterY = perpendicularSlope * circleCenterX + intercept;
         HOperatorSet.LineOrientation(row, column, circleCenterY, circleCenterX, out HTuple phi);
         HOperatorSet.TupleSin(phi, out HTuple sin);
         HOperatorSet.TupleCos(phi, out HTuple cos);
         HTuple TY = new HTuple(), TX = new HTuple();
         for (int i = -22; i < 22; i++)
         {
             Module.PointMeasure_(Image, row+i*cos*3, column+i*sin*3, (ResultRowBegin + ResultRowBegin2) / 2, (ResultColumnBegin + ResultColumnBegin2) / 2, 1, 1, 40, out HTuple resultRow, out HTuple resultColumn);
             HOperatorSet.TupleLength(resultRow, out HTuple length);
             if (length!=1)
             {
                 continue;
             }
             TY[i+22] = resultRow;
             TX[i+22] = resultColumn;
         }
         HOperatorSet.GenContourPolygonXld(out HObject contours, TY, TX);
         HOperatorSet.FitCircleContourXld(contours, "atukey", -1, 0, 0, 3, 2,
             out HTuple SpinRow, out HTuple SpinColumn, out HTuple Radius, out HTuple StartPhi,
             out HTuple EndPhi, out HTuple PointOrder);
         HOperatorSet.GenCircleContourXld(out Circle, SpinRow, SpinColumn, Radius, 0, Math.PI*2, new HTuple("positive"), 1);
         R = Radius;
         return true;

     }
     catch (Exception)
     {
         return false;
     }
 }

 #endregion
#region // 直线查找
/// <summary>
/// 直线查找
/// </summary>
/// <param name="image">输入图像</param>
/// <param name="BeginRow">输入ROI的开始横坐标</param>
/// <param name="EndRow">输入ROI的结束横坐标</param>
/// <param name="BeginColumn">输入ROI开始列坐标</param>
/// <param name="EndColumn">输入ROI的结束列坐标</param>
/// <param name="MeasureHeight">输入测量矩形高度</param>
/// <param name="MeasureWide">输入测量矩形宽度</param>
/// <param name="Sigma">输入测量矩形的高斯滤波值</param>
/// <param name="Threshold">输入最小边缘对比度</param>
/// <param name="Measure_Set">选择拟合边1(“uniform”:最接近ROI轮廓的拟合边;“positive”:由亮到暗,“negative”:由暗到亮)</param>
/// <param name="Measure_Place">选择拟合边2(“first”:所有轮廓的第一条边,“last”:所有轮廓的最后一个边,“all”:最接近ROI轮廓的拟合边)</param>
/// <param name="LineContours">结果轮廓</param>
/// <param name="ResultRowBegin">结果轮廓开始横坐标</param>
/// <param name="ResultRowEnd">结果轮廓结束横坐标</param>
/// <param name="ResultColumnBegin">结果轮廓开始列坐标</param>
/// <param name="ResultCloumnEnd">结果轮廓结束列坐标</param>
/// <returns>拟合成功返回true,拟合失败返回false</returns>
static public bool LineMeasure_(HObject image, HTuple BeginRow, HTuple BeginColumn, HTuple EndRow, 
            HTuple EndColumn, HTuple MeasureHeight, HTuple MeasureWide, HTuple Sigma, HTuple Threshold,
            HTuple Measure_Set, HTuple Measure_Place, out HObject LineContours,
            out HTuple ResultRowBegin, out HTuple ResultColumnBegin, out HTuple ResultRowEnd, 
            out HTuple ResultCloumnEnd)
{
    HOperatorSet.GenEmptyObj(out LineContours);
    ResultRowBegin = null;
    ResultColumnBegin = null;
    ResultCloumnEnd = null;
    ResultRowEnd = null;
    try
    {

        HOperatorSet.CreateMetrologyModel(out HTuple metrologyHandle);
        HOperatorSet.AddMetrologyObjectLineMeasure(metrologyHandle, BeginRow, BeginColumn, EndRow, EndColumn,
                MeasureHeight, MeasureWide, Sigma, Threshold, new HTuple(), new HTuple(), out HTuple index);

        HOperatorSet.SetMetrologyObjectParam(metrologyHandle, new HTuple("all"), (new HTuple("measure_transition")
                                 ).TupleConcat("measure_select"), (new HTuple(Measure_Set)
                                 ).TupleConcat(Measure_Place));
        //HOperatorSet.SetMetrologyObjectParam(metrologyHandle, new HTuple("all"), new HTuple("min_score"), 0.1);
        HOperatorSet.ApplyMetrologyModel(image, metrologyHandle);
        HOperatorSet.GetMetrologyObjectResultContour(out LineContours, metrologyHandle, new HTuple("all"), new HTuple("all")
                , new HTuple(1.5));
        HOperatorSet.GetMetrologyObjectResult(metrologyHandle, index, new HTuple("all"), new HTuple("result_type"),
                       new HTuple("row_begin"), out ResultRowBegin);
        HOperatorSet.GetMetrologyObjectResult(metrologyHandle, index, new HTuple("all"), new HTuple("result_type"),
                    new HTuple("row_end"), out ResultRowEnd);
        HOperatorSet.GetMetrologyObjectResult(metrologyHandle, index, new HTuple("all"), new HTuple("result_type"),
                    new HTuple("column_begin"), out ResultColumnBegin);
        HOperatorSet.GetMetrologyObjectResult(metrologyHandle, index, new HTuple("all"), new HTuple("result_type"),
                    new HTuple("column_end"), out ResultCloumnEnd);
        HOperatorSet.TupleLength(ResultRowBegin, out HTuple length);
        if (length == 0)
        {
            return false;
        }
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }


}
#endregion

2.2程序讲解

2.2.1读取图像和绘制ROI,并找到直线

 bool line1 = false, line2 = false;
 if (FastSet)
 {
     line1 = Module.LineMeasure_(Image, BeginRow1, BeginCloumn1, EndRow1,  EndCloumn1, 10, 2, 1, 40, "uniform", "first", out LineContours,
             out ResultRowBegin, out ResultColumnBegin, out ResultRowEnd,  out ResultCloumnEnd);
     line2 = Module.LineMeasure_(Image, BeginRow2, BeginCloumn2, EndRow2,  EndCloumn2, 10, 2, 1, 40, "uniform", "first", out LineContours2,
             out ResultRowBegin2, out ResultColumnBegin2, out ResultRowEnd2,  out ResultCloumnEnd2);
 }
 if (!line1 || !line2)
 {
     return false;
 }

首先根据初始图像和直线ROI进行直线测量,找到我们所需要输出的直线。

2.2.2求取直线角度和交点

 
                HOperatorSet.IntersectionLines(BeginRow1, BeginCloumn1, EndRow1, EndCloumn1, BeginRow2, BeginCloumn2, EndRow2, EndCloumn2,
                            out HTuple row, out HTuple column, out HTuple isOverlapping);
                HOperatorSet.LineOrientation( ResultRowBegin,  ResultColumnBegin,  ResultRowEnd,  ResultCloumnEnd, out HTuple phi1);
                HOperatorSet.LineOrientation(ResultRowBegin2,  ResultColumnBegin2,  ResultRowEnd2,  ResultCloumnEnd2, out HTuple phi2);

2.2.3求2条直线的内切圆

由于只有2条直线,所以我们是绘制内切圆是默认以终点坐标为结束区域绘制


                double midX = (ResultColumnBegin + ResultColumnBegin2) / 2;
                double midY = (ResultRowBegin + ResultRowBegin2) / 2;
                // 计算两条直线的垂直平分线的斜率
                double perpendicularSlope = -1 / ((phi1 + phi2) / 2);

                // 计算垂直平分线的截距
                double intercept = midY - perpendicularSlope * midX;

                // 计算圆心坐标
                double circleCenterX = -perpendicularSlope * intercept / (perpendicularSlope * perpendicularSlope + 1);
                double circleCenterY = perpendicularSlope * circleCenterX + intercept;

2.2.4生成垂直采样线,和采样拟合弧线

HOperatorSet.LineOrientation(row, column, circleCenterY, circleCenterX, out HTuple phi);
HOperatorSet.TupleSin(phi, out HTuple sin);
HOperatorSet.TupleCos(phi, out HTuple cos);
HTuple TY = new HTuple(), TX = new HTuple();
for (int i = -22; i < 22; i++)
{
    Module.PointMeasure_(Image, row+i*cos*3, column+i*sin*3, (ResultRowBegin + ResultRowBegin2) / 2, (ResultColumnBegin + ResultColumnBegin2) / 2, 1, 1, 40, out HTuple resultRow, out HTuple resultColumn);
    HOperatorSet.TupleLength(resultRow, out HTuple length);
    if (length!=1)
    {
        continue;
    }
    TY[i+22] = resultRow;
    TX[i+22] = resultColumn;
}
HOperatorSet.GenContourPolygonXld(out HObject contours, TY, TX);
HOperatorSet.FitCircleContourXld(contours, "atukey", -1, 0, 0, 3, 2,
    out HTuple SpinRow, out HTuple SpinColumn, out HTuple Radius, out HTuple StartPhi,
    out HTuple EndPhi, out HTuple PointOrder);
HOperatorSet.GenCircleContourXld(out Circle, SpinRow, SpinColumn, Radius, 0, Math.PI*2, new HTuple("positive"), 1);
R = Radius;

Halcon测量专栏-圆倒角-LMLPHP

总结

圆倒角测量在很多机械设计上有使用到,与圆度测量一致,都具有测量难度大,费时,且精度不够的问题

03-12 15:37