欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于halcon的形状模板轮廓筛选

程序员文章站 2022-03-16 17:47:10
...

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

场景

有需求,才会去做。有时候,在一张质量不怎么好的图像上做模板,比如,有很多干扰点、背景或者其他不想要的轮廓,除了生成模板后,再慢慢去用橡皮擦来擦除它,还有一种更直接了当的方法:筛选。

CV时刻

bool GenDesiredContours(const HXLD& srcContours, HXLD& dstContours, 
                       QPoint length, QPointF circularity, int delta = 0, int contourNum = 0);

参数1 :srcContours,输入的原始轮廓,一般先生成模板,然后Get~
参数2 :dstContours,输出筛选后的轮廓,用来重新生成模板;
参数3 :length,为筛选轮廓的最小长度值;
参数4 :circularity,为筛选轮廓的圆度值;
参数5 :delta,为依靠相邻轮廓的偏差值来判断,后续的轮廓还要不要了;
参数6 :contourNum,直接粗暴,指明就要最长的几个轮廓。

bool HalconUnity::GenDesiredContours(const HXLD& srcContours, HXLD& dstContours, 
QPoint length, QPointF circularity, int delta, int contourNum)
{
    try
    {
        HXLDtempXLDList, selectObj;
        HTuple selectXLDNum, xldLength, xldSimilarity;
        QMap<int, int> xldLengthMap;
        QList<int> xldLengthList;
        CountObj(srcContours, &selectXLDNum);
        //UnionAdjacentContoursXld(srcContours, &tempXLDList, 10, 1, "attr_keep");
        UnionCocircularContoursXld(srcContours, &tempXLDList, 1, 0, 0, 15, 5, 5, "false", 1);
        UnionCollinearContoursExtXld(tempXLDList, &tempXLDList, 10, 1, 2, 0.1, 0, -1, 1, 1, 1, 1, 1, 0, "attr_keep");

        double lengthMin, lengthMax, circularityMax;
        length.x() > 0 ? lengthMin = length.x() : lengthMin = 10;
        length.y() > 0 ? lengthMax = length.y() : lengthMax = 999999;
        circularity.y() > 0 ? circularityMax = circularity.y() : circularityMax = 1.0;
        SelectContoursXld(tempXLDList, &tempXLDList, "contour_length", lengthMin, lengthMax, 0, 0);
        CountObj(tempXLDList, &selectXLDNum);
        
        for (int i = 1; i <= selectXLDNum[0].I(); i++)
        {
            SelectObj(tempXLDList, &selectObj, i);
            CircularityXld(selectObj, &xldSimilarity);
            
            if (xldSimilarity[0].D() < circularity.x() || xldSimilarity[0].D() > circularityMax)
            {
                continue;
            }

            LengthXld(selectObj, &xldLength);
            xldLengthMap.insert(i, (int)xldLength[0].D());
            xldLengthList.append((int)xldLength[0].D());
        }

	qSort(xldLengthList);
        int judgeMaxXld = xldLengthList.length();

	if (judgeMaxXld > 2)
        {
            //参数筛选
            if (contourNum > 0.0)
            {
                if (judgeMaxXld > contourNum)
                {
                    judgeMaxXld = contourNum;
                }
            }
	    //else if (percent > 0)
            //{
            //    if ((judgeMaxXld * percent * 0.01) >= 2.0)
            //    {
            //        judgeMaxXld = (int)(judgeMaxXld * percent * 0.01);
            //    }
            //    else
            //    {
            //        judgeMaxXld -= 1;
            //    }
            //}
	
	    //差值判断
            if (delta > 0.0)
            {
                for (int j = judgeMaxXld - 2; j >= 0; j--)
                {
                    if (j > 0 && xldLengthList[j] - xldLengthList[j - 1] > delta)
                    {
                        xldLengthList = xldLengthList.mid(j);
                        judgeMaxXld = xldLengthList.length();
                        break;
                    }
                }
            }
            
            //标准差
            //{
            //    double sum = 0.0;
            //    double mean = 0.0;
            //    double variance = 0.0;
            //    double stdDeviation = 0.0;
            //    int i = 0;

	    //    for (i = 0; i < judgeMaxXld; ++i)
            //    {
            //        sum += xldLengthList[i];
            //    }

	    //    mean = sum / judgeMaxXld;
            //    for (i = 0; i < judgeMaxXld; ++i)
            //    {
            //        variance += pow(xldLengthList[i] - mean, 2);
            //    }
  	    //    stdDeviation = sqrt(variance / judgeMaxXld);

	    //    for (i = judgeMaxXld - 1; i >= 0; i--)
            //    {
            //        if (xldLengthList[i] < stdDeviation)
            //        {
            //            xldLengthList = xldLengthList.mid(i + 1);
            //            judgeMaxXld = xldLengthList.length();
            //            break;
            //        }
            //    }
            //}
         }
	    
	 int count = 0;
	
	for (int i = xldLengthList.length() - 1; i >= 0; i--)
        {
            QMap<int, int>::iterator iter = xldLengthMap.begin();
            while (iter != xldLengthMap.end())
            {
                if (iter.value() == xldLengthList[i])
                {
                    SelectObj(tempXLDList, &selectObj, iter.key());
                    if (dstContours.IsInitialized())
                    {
                        ConcatObj(dstContours, selectObj, &dstContours);
                    }
                    else
                    {
                        dstContours = selectObj;
                    }
                    count++;
                    if (count >= judgeMaxXld)
                    {
                        return true;
                    }
                    iter = xldLengthMap.erase(iter);
                    }
                else
                {
                    iter++;
                }
            }
        }
    }
    catch (HException& ex)
    {
        HandleLog::LogHalconHExcept(ex, ILogger::LogLevel::LL_INFO);
    }
    catch (...)
    {
    }
    
    return false;
}

注意

1.二次创建

筛选出来的轮廓,可以直接用CreateScaledShapeModelXld创建模板,但这个比较麻烦:如果轮廓线还是比较多、比较复杂的话,很耗时。所以我一般是再把轮廓转为区域,然后再用区域去创建模板。

2.轮廓显示

注意二次创建模板后,不要直接用新的轮廓或者区域的中心点去仿射变换,应该还是用原来第一次创建模板的区域去做变换,不然你的模板轮廓会错位显示,很尴尬。

相关标签: 视觉