基于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.轮廓显示
注意二次创建模板后,不要直接用新的轮廓或者区域的中心点去仿射变换,应该还是用原来第一次创建模板的区域去做变换,不然你的模板轮廓会错位显示,很尴尬。
上一篇: CSS3 动画