基于halcon的直线查找之卡尺

我这人比较懒得罗里吧嗦,基本都是直接说两点:why?how?

基于halcon的直线查找之卡尺

直线的检测在halcon中主要有两种方式:直线拟合和卡尺直线。这里分享卡尺方法,拟合请移步:直线拟合

直线卡尺

首先把整体思路列出来:
CreateMetrologyModel创建一个测量句柄;
AddMetrologyObjectLineMeasure添加一个线“Line”的模型;
SetMetrologyObjectParam设置相关测量参数。比如:卡尺垂直于边的长度,卡尺的宽度,卡尺的个数,保留的卡尺个数,边缘最低对比度等;
ApplyMetrologyModel开始找边;
GetMetrologyObjectMeasuresGetMetrologyObjectResultContour将找到的边界结果显示,同时获得每个卡尺找到的点坐标。

是不是很简单?没错,就这么简单无脑。作为调包侠,是还是觉得用的算子有点多啊…感觉给别人用这么多函数有点low?那就自己再封一层壳吧,瞬间高大上了。

CTRL + CV时刻

直接copy拿去用吧

// 代码量有点冗杂,很多参数判断。起始作为底层供调用的方法,无需写这些判断,推荐判断安全性的问题应该交给上层调用者来保证,底层保证效率就行,避免上层判断,底层又判断,造成重复耗时。可以删掉,从CreateMetrologyModel开始。

void FindLineCaliper(HObject ho_Image, HObject* ho_ResultContour, HObject* ho_MeasureContour,
    HTuple hv_Row1, HTuple hv_Column1, HTuple hv_Row2, HTuple hv_Column2, HTuple hv_MeasureLength,
    HTuple hv_MeasureWidth, HTuple hv_MeasureSigma, HTuple hv_MeasureThreshold, HTuple hv_NumInstances,
    HTuple hv_MeasureSelect, HTuple hv_MeasureTransition, HTuple hv_NumMeasures,
    HTuple* hv_LineFind, HTuple* hv_RowStart, HTuple* hv_ColumnStart, HTuple* hv_RowEnd,
    HTuple* hv_ColumnEnd, HTuple* hv_RowFrame, HTuple* hv_ColumnFrame)
{
    HObject  ho_MeasuredLines;
    HTuple  hv_num_instances, hv_measure_select, hv_measure_transition;
    HTuple  hv_num_measures, hv_ValueName, hv_Value, hv_Channels;
    HTuple  hv_Width, hv_Height, hv_IsNumber, hv_Index, hv_Index1;
    HTuple  hv_IsString, hv_NumMatches1, hv_NumMatches2, hv_IsString1;
    HTuple  hv_NumMatches3, hv_NumMatches4, hv_MetrologyHandle;
    HTuple  hv_IndexLine, hv_RowMeasure, hv_ColumnMeasure, hv_IndexSearch;
    HTuple  hv_Frame_Parameter, hv_Index2, hv_NumMatches5, hv_NumMatches6;;
    //*********找直线函数**********
    //****输入参数:Image:输入图像, 需要单通道图像*****
    //****输入参数:Row1,Column1,Row2,Column2:找直线的参考基准线, 其位置与需要找的直线位置相同或近似平行*****
    //****输入参数:MeasureLength,MeasureWidth,MeasureSigma,MeasureThreshold:卡尺的长宽, Sigma值和阈值,支持数组输入*****
    //****输入参数:ParameterName,ParameterValue:检测控制参数名称和值, 具体请见下表*****
    //****输入参数: NumInstances: 检测的直线数量,必须为正整数***
    //****输入参数: NumMeasures: 检测的卡尺数量*****
    //****输入参数:MeasureTransition:找线的方式, 由暗到明, 由明到暗,只能是'positive'或'negative'*****
    //****输入参数:MeasureSelect: 每个卡尺内找到的点是最近点还是最远点, 只能是'first'或'last'*****
    //****输出参数:LineFind: 0:无法找到直线;1:可以找到直线*****
    //****输出参数:RowStart,ColumnStart,RowEnd,ColumnEnd:找到的直线起点与终点的坐标*****
    //****输出参数:ResultContour:生成的直线图形*****
    //****输出参数:MeasureContour:生成的卡尺图形*****
    //****输出参数:RowFrame,ColumnFrame:每个卡尺找到的点的坐标*****
    //****函数作者:*****
    //****更新时间:*****
    //******************
    //****默认参数值*****
    //******************
    (*hv_LineFind) = 0;
    (*hv_RowStart) = 0;
    (*hv_ColumnStart) = 0;
    (*hv_RowEnd) = 0;
    (*hv_ColumnEnd) = 0;
    (*hv_RowFrame) = HTuple();
    (*hv_ColumnFrame) = HTuple();
    hv_num_instances = 1;
    hv_measure_select = "last";
    hv_measure_transition = "positive";
    hv_num_measures = 40;
    hv_ValueName.Clear();
    hv_ValueName[0] = "num_instances";
    hv_ValueName[1] = "num_measures";
    hv_ValueName[2] = "measure_transition";
    hv_ValueName[3] = "measure_select";
    //****参数类型和范围确认*****
    //****int/real 型:['int',min,max], min=<输入值<=max,上下限若是无穷大,则写作'' *****
    //****string 型:['string','a','b',...,'z'],输入值需是'a','a','b',...,'z'中的任意一个值*****
    hv_Value.Clear();
    hv_Value[0] = "int";
    hv_Value[1] = 1;
    hv_Value[2] = "";
    hv_Value[3] = "int";
    hv_Value[4] = 1;
    hv_Value[5] = "";
    hv_Value[6] = "string";
    hv_Value[7] = "positive";
    hv_Value[8] = "negative";
    hv_Value[9] = "string";
    hv_Value[10] = "first";
    hv_Value[11] = "last";
    //*************************************
    //****1.判断输入参数是否满足计算要求*****
    //*************************************
    //****a.判断输入图像是否为单通道图像*****
    CountChannels(ho_Image, &hv_Channels);

    if (0 != (hv_Channels != 1))
    {
        Rgb1ToGray(ho_Image, &ho_Image);
    }

    GetImageSize(ho_Image, &hv_Width, &hv_Height);
    //****b.判断输入的直线参数是否为number,若出现非数字格式的输入情况,则直接返回*****
    TupleIsNumber((((((((hv_Row1.TupleConcat(hv_Column1)).TupleConcat(hv_Row2)).TupleConcat(hv_Column2)).TupleConcat(hv_MeasureLength)).TupleConcat(hv_MeasureWidth)).TupleConcat(hv_MeasureThreshold)).TupleConcat(hv_NumInstances)).TupleConcat(hv_NumMeasures),
        &hv_IsNumber);
    {
        HTuple end_val50 = (hv_IsNumber.TupleLength()) - 1;
        HTuple step_val50 = 1;

        for (hv_Index = 0; hv_Index.Continue(end_val50, step_val50); hv_Index += step_val50)
        {
            if (0 != (HTuple(hv_IsNumber[hv_Index]) == 0))
            {
                return;
            }
        }
    }
    //****判断输入参数名称和数值的类型是否正确*****
    //****MeasureLeght≥1*****
    {
        HTuple end_val58 = (hv_MeasureLength.TupleLength()) - 1;
        HTuple step_val58 = 1;

        for (hv_Index1 = 0; hv_Index1.Continue(end_val58, step_val58); hv_Index1 += step_val58)
        {
            if (0 != (HTuple(hv_MeasureLength[hv_Index1]) < 1))
            {
                hv_MeasureLength[hv_Index1] = 1;
            }
        }
    }
    //****MeasureWidth≥1*****
    {
        HTuple end_val65 = (hv_MeasureWidth.TupleLength()) - 1;
        HTuple step_val65 = 1;

        for (hv_Index1 = 0; hv_Index1.Continue(end_val65, step_val65); hv_Index1 += step_val65)
        {
            if (0 != (HTuple(hv_MeasureWidth[hv_Index1]) < 1))
            {
                hv_MeasureWidth[hv_Index1] = 1;
            }
        }
    }
    //****MeasureSigma≥0.4*****
    {
        HTuple end_val72 = (hv_MeasureSigma.TupleLength()) - 1;
        HTuple step_val72 = 1;

        for (hv_Index1 = 0; hv_Index1.Continue(end_val72, step_val72); hv_Index1 += step_val72)
        {
            if (0 != (HTuple(hv_MeasureSigma[hv_Index1]) < 0.4))
            {
                hv_MeasureSigma[hv_Index1] = 0.4;
            }
        }
    }
    //****MeasureThreshold≥1, MeasureThreshold≤255*****
    {
        HTuple end_val79 = (hv_MeasureThreshold.TupleLength()) - 1;
        HTuple step_val79 = 1;

        for (hv_Index1 = 0; hv_Index1.Continue(end_val79, step_val79); hv_Index1 += step_val79)
        {
            if (0 != (HTuple(hv_MeasureThreshold[hv_Index1]) < 1))
            {
                hv_MeasureThreshold[hv_Index1] = 1;
            }

            if (0 != (HTuple(hv_MeasureThreshold[hv_Index1]) > 255))
            {
                hv_MeasureThreshold[hv_Index1] = 255;
            }
        }
    }
    //****NumInstances ≥1*****
    TupleInt(hv_NumInstances, &hv_num_instances);

    if (0 != (hv_num_instances < 1))
    {
        hv_num_instances = 1;
    }

    //****NumMeasures ≥1******
    TupleInt(hv_NumMeasures, &hv_num_measures);

    if (0 != (hv_num_measures < 1))
    {
        hv_num_measures = 1;
    }

    //****MeasureTransion: 'positive' or 'negative'*****
    TupleIsString(hv_MeasureTransition, &hv_IsString);

    if (0 != hv_IsString)
    {
        TupleRegexpTest(hv_MeasureTransition, (HTuple("positive").Append("ignore_case")), &hv_NumMatches1);

        if (0 != (hv_NumMatches1 == 1))
        {
            hv_measure_transition = "positive";
        }

        TupleRegexpTest(hv_MeasureTransition, (HTuple("negative").Append("ignore_case")), &hv_NumMatches2);

        if (0 != (hv_NumMatches2 == 1))
        {
            hv_measure_transition = "negative";
        }

        TupleRegexpTest(hv_MeasureTransition, (HTuple("all").Append("ignore_case")), &hv_NumMatches3);

        if (0 != (hv_NumMatches3 == 1))
        {
            hv_measure_transition = "all";
        }
    }

    //****MeasureSelect: 'first' or 'last'*****
    TupleIsString(hv_MeasureSelect, &hv_IsString1);

    if (0 != hv_IsString1)
    {
        TupleRegexpTest(hv_MeasureSelect, (HTuple("first").Append("ignore_case")), &hv_NumMatches4);

        if (0 != (hv_NumMatches4 == 1))
        {
            hv_measure_select = "first";
        }

        TupleRegexpTest(hv_MeasureSelect, (HTuple("last").Append("ignore_case")), &hv_NumMatches5);

        if (0 != (hv_NumMatches5 == 1))
        {
            hv_measure_select = "last";
        }

        TupleRegexpTest(hv_MeasureSelect, (HTuple("all").Append("ignore_case")), &hv_NumMatches6);

        if (0 != (hv_NumMatches6 == 1))
        {
            hv_measure_select = "all";
        }
    }

    //********************
    //****2.找直线函数*****
    //********************
    CreateMetrologyModel(&hv_MetrologyHandle);
    //****添加多个直线寻找---3/7*****
    //for Index3 := 0 to |MeasureLength|-1 by 1
    //for Index4 := 0 to |MeasureWidth|-1 by 1
    //for Index5 := 0 to |MeasureSigma|-1 by 1
    //for Index6 := 0 to |MeasureThreshold|-1 by 1
    //set_metrology_model_image_size (MetrologyHandle, Width, Height)
    //add_metrology_object_line_measure (MetrologyHandle, Row1, Column1, Row2, Column2, MeasureLength[Index3], MeasureWidth[Index4], MeasureSigma[Index5], MeasureThreshold[Index6], [], [], IndexLine)
    //endfor
    //endfor
    //endfor
    //endfor
    //add_metrology_object_line_measure (MetrologyHandle, Row1, Column1, Row2, Column2, MeasureLength, MeasureWidth, MeasureSigma, MeasureThreshold, [], [], Index)
    SetMetrologyModelImageSize(hv_MetrologyHandle, hv_Width, hv_Height);
    AddMetrologyObjectLineMeasure(hv_MetrologyHandle, hv_Row1, hv_Column1, hv_Row2,
        hv_Column2, hv_MeasureLength, hv_MeasureWidth, hv_MeasureSigma, hv_MeasureThreshold,
        HTuple(), HTuple(), &hv_IndexLine);
    SetMetrologyObjectParam(hv_MetrologyHandle, "all", "num_instances", hv_num_instances);
    SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_select", hv_measure_select);
    SetMetrologyObjectParam(hv_MetrologyHandle, "all", "measure_transition", hv_measure_transition);
    SetMetrologyObjectParam(hv_MetrologyHandle, "all", "num_measures", hv_num_measures);
    ApplyMetrologyModel(ho_Image, hv_MetrologyHandle);

    if (0 != (hv_IndexLine > 0))
    {
        GetMetrologyObjectMeasures(&(*ho_MeasureContour), hv_MetrologyHandle, "all", "all", &hv_RowMeasure, &hv_ColumnMeasure);
        GetMetrologyObjectResultContour(&ho_MeasuredLines, hv_MetrologyHandle, "all", "all", 1.5);
        (*hv_LineFind) = 1;
    }
    else
    {
        (*hv_LineFind) = 0;
    }

    //**********************
    //****3.获取直线参数*****
    //**********************
    {
        HTuple end_val163 = hv_IndexLine;
        HTuple step_val163 = 1;

        for (hv_IndexSearch = 0; hv_IndexSearch.Continue(end_val163, step_val163); hv_IndexSearch += step_val163)
        {
            GetMetrologyObjectResult(hv_MetrologyHandle, hv_IndexSearch, "all", "result_type", "all_param", &hv_Frame_Parameter);

            if (0 != ((hv_Frame_Parameter.TupleLength()) == (hv_num_instances * 4)))
            {
                (*hv_LineFind) = 1;
                {
                    HTuple end_val167 = ((hv_Frame_Parameter.TupleLength()) / 4) - 1;
                    HTuple step_val167 = 1;

                    for (hv_Index2 = 0; hv_Index2.Continue(end_val167, step_val167); hv_Index2 += step_val167)
                    {
                        (*hv_RowStart)[hv_Index2] = HTuple(hv_Frame_Parameter[hv_Index2 * hv_num_instances]);
                        (*hv_ColumnStart)[hv_Index2] = HTuple(hv_Frame_Parameter[(hv_Index2 * hv_num_instances) + 1]);
                        (*hv_RowEnd)[hv_Index2] = HTuple(hv_Frame_Parameter[(hv_Index2 * hv_num_instances) + 2]);
                        (*hv_ColumnEnd)[hv_Index2] = HTuple(hv_Frame_Parameter[(hv_Index2 * hv_num_instances) + 3]);
                    }
                }
            }

            if (0 != (HTuple((*hv_LineFind) == 1).TupleOr(hv_IndexSearch == hv_IndexLine)))
            {
                GetMetrologyObjectResultContour(&(*ho_ResultContour), hv_MetrologyHandle, hv_IndexSearch, "all", 1.5);
                GetMetrologyObjectMeasures(&(*ho_MeasureContour), hv_MetrologyHandle, hv_IndexSearch, "all", &(*hv_RowFrame), &(*hv_ColumnFrame));
                ClearMetrologyModel(hv_MetrologyHandle);
                break;
            }
        }
    }
    return;
}

注意

我还有更简洁的版本

你可能感兴趣的:(机器视觉,经验分享)