东南大学RM装甲板识别算法详解
2020-12-13 14:40
标签:模板匹配 remove ring min 相减 fill asp rop 循环 rm中,装甲板的识别在比赛中可谓是最基础的算法。而在各个开源框架中,该算法也可以说最为成熟。出于学习目的,之后将对比多个高校或网络代码(),尝试学习各个rm装甲板识别算法的优点和流程。 先将 下面这段代码先不要看,等到下述中出现“请回到顶部”字样的时候观看 进行膨胀处理,将二值图中的灯条变粗。 寻找轮廓,将找到的轮廓放置在 之后是一个大循环来检测轮廓中的灯条。具体操作作为注释 到这里,已经将各可能的灯条放入到 而识别装甲板算法(也就是原文中的 东南大学RM装甲板识别算法详解 标签:模板匹配 remove ring min 相减 fill asp rop 循环 原文地址:https://www.cnblogs.com/IaCorse/p/11567363.html
这次先是东南大学(SEU-SuperNova-CVRA)开源的视觉算法:
cv::Mat binBrightImg;
cvtColor(_roiImg, _grayImg, COLOR_BGR2GRAY, 1);
cv::threshold(_grayImg, binBrightImg, _param.brightness_threshold, 255, cv::THRESH_BINARY);
_roiImg
转成灰度图,方便后续转成二值图。
之后再将上图转为二值图,放到binBrightImg
中,这里的_param.brightness_threshold
是阈值,应用的为cv::THRESH_BINARY
的方法。个人认为这里的方法还可以用CV_THRESH_OTSU
也就是大津算法,效率有待后续测试。// 把一个3通道图像转换成3个单通道图像
split(_roiImg,channels);//分离色彩通道
//预处理删除己方装甲板颜色
if(_enemy_color==RED)
_grayImg=channels.at(2)-channels.at(0);//Get red-blue image;
else _grayImg=channels.at(0)-channels.at(2);//Get blue-red image;
————————————————
版权声明:本文为CSDN博主「Raring_Ringtail」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010750137/article/details/96428059
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
dilate(binBrightImg, binBrightImg, element);
vector
lightcountours
中,而这一步据网上说是相对费时的一段时间,其很大程度决定于前文的预处理情况。for(const auto& contour : lightContours)//对每个轮廓都进行处理
{
//得到轮廓的面积//
float lightContourArea = contourArea(contour);
//筛选掉噪声//
if(contour.size() _param.light_max_ratio ||
lightContourArea / lightRec.size.area() lightVertex;
for(int i = 0; i 20.0)) || (_enemy_color == RED && meanVal[RED] - meanVal[BLUE] > 20.0))
{
lightInfos.push_back(LightDescriptor(lightRec));
}
//若使用了两通道值相减的方法,则这里可以直接将结果保存下来。注意放入的是lightrec而不是lightrect的外接矩形信息
//lightInfos.push_back(LightDescriptor(lightRec));
lightInfos
中去了,可是我们的目的是找到装甲板,所以下面的代码将会在这方面展开: //检查是否检测到灯条//
if(lightInfos.empty())
{
return _flag = ARMOR_NO;
}
}//循环结束
{
//用到了C++11的lambda(可简单看作函数对象),设置了ld1和ld2两个参数,依照灯条中心的x坐标从左到右(opencv的坐标轴为横x竖y)。center为point2f类型的。//
sort(lightInfos.begin(), lightInfos.end(), [](const LightDescriptor& ld1, const LightDescriptor& ld2)
{
return ld1.center.x minRightIndices(lightInfos.size(), -1);
//遍历每一种组合//
for(size_t i = 0; i _param.light_max_angle_diff_ ||
LenDiff_ratio > _param.light_max_height_diff_ratio_)
{
continue;
}
/*
* proper location: // y value of light bar close enough
* // ratio of length and width is proper
*/
//计算左右灯条中心距离//
float dis = cvex::distance(leftLight.center, rightLight.center);
//计算左右灯条长度的均值//
float meanLen = (leftLight.length + rightLight.length) / 2;
//灯条y的差//
float yDiff = abs(leftLight.center.y - rightLight.center.y);
//y差值的比率//
float yDiff_ratio = yDiff / meanLen;
//同前//
float xDiff = abs(leftLight.center.x - rightLight.center.x);
float xDiff_ratio = xDiff / meanLen;
//灯条的距离与长度的比值(也就是嫌疑装甲板长和宽的比值)//
float ratio = dis / meanLen;
//对上面各量筛选,如果y差太大(y最好越相近越好),或者x差的太小,又或者装甲板长宽比不合适就排除掉。//
if(yDiff_ratio > _param.light_max_y_diff_ratio_ ||
xDiff_ratio _param.armor_max_aspect_ratio_ ||
ratio _param.armor_big_armor_ratio ? BIG_ARMOR : SMALL_ARMOR;
// calculate the rotation score
float ratiOff = (armorType == BIG_ARMOR) ? max(_param.armor_big_armor_ratio - ratio, float(0)) : max(_param.armor_small_armor_ratio - ratio, float(0));
float yOff = yDiff / meanLen;
//应该是rotationScore越接近0越好,看后续用处//
float rotationScore = -(ratiOff * ratiOff + yOff * yOff);
//生成相应的装甲板//
ArmorDescriptor armor(leftLight, rightLight, armorType, _grayImg, rotationScore, _param);
//将获得的嫌疑装甲板放到armors中去//
_armors.emplace_back(armor);
break;
}
}
//此处删除debug内容//
//没找到的话。。//
if(_armors.empty())
{
return _flag = ARMOR_NO;
}
}
//此处删除调试信息//
//delete the fake armors
_armors.erase(remove_if(_armors.begin(), _armors.end(), [](ArmorDescriptor& i)
{
//这里就是识别装甲板的算法了//
return !(i.isArmorPattern());
}), _armors.end());
//江达小记版本//
_armors.erase(remove_if(_armors.begin(), _armors.end(), [this](ArmorDescriptor& i)
{//lamdba函数判断是不是装甲板,将装甲板中心的图片提取后让识别函数去识别,识别可以用svm或者模板匹配等
return 0==(i.isArmorPattern(_small_Armor_template,_big_Armor_template,lastEnemy));
} ), _armors.end());
//没有一个是装甲板的情况//
if(_armors.empty())
{
_targetArmor.clear();
//看是目标丢失还是没识别出来//
if(_flag == ARMOR_LOCAL)
{
//cout b.finalScore;
});
_targetArmor = _armors[0];
//update the flag status
_trackCnt++;
i.isArmorPattern()
)等后续有机会再准备。