MOD算法
前言
MOD的全称是移动目标障碍物检测,目前手里有一套古老的代码来实现的,用的是MOG2和VIBE算法这些,这些算法用不到神经网络,还是我在学校打比赛,做岗哨机器人使用的。可惜组内人员有限,也没有足够的动力转成采用神经网络来实现这个MOD功能。所以用大模型简单的调试一下吧。
正文
这里会这里的代码核心逻辑和细节写在这里。
首先,要梳理出整个算法的输入和输出。输入包括:BEV的鸟瞰图、汽车速度、时间戳、汽车挡位信息。输出就是某个方向的报警信息。
具体流程来说,运动状态的判断:
1、第一步进行图像预处理,a、对于输入的环视拼接图转成灰度图;b、通过当前汽车速度、时间戳、汽车的两次瞬移变化来判断当前的图像是否合理。c、判断图像是否模糊,这里主要通过梯度辐值、通过幅值的均值和方差判断是否在合理的范围内。
//用来评估模糊的经典组合
cv::Laplacian(matImageGray, dst, CV_16S, 3);
cv::convertScaleAbs( dst, abs_dst );
cv::meanStdDev(abs_dst, mu, stddev);
2、第二步需要通过光流法计算汽车的运动状态。主要还是依赖opencv库中的特征金字塔实现(docs.opencv.org/4.x/db/d7f/…
a、主要接口:calcOpticalFlowPyrLK(prevGray, imgGray, points[0], points[1], status, err, winSize, 3, termcrit, 0, 0.001);
prevGray : 上一时刻的图片;
imgGray: 当前时刻的图片;
points[0]: 需要追踪的特征点;
points[1]:追踪后的特征点;
status: 表示追踪的点是否成功;
winSize:表示特征金字塔检索窗口
maxlevel: 如果是0,则表示在原始分辨率;如果是3,则是表示搜索三层。
termcrit: 表示终止条件;
b、cv::Mat homography = cv::findHomography(pt2, pt1, homoMask, cv::RANSAC); 根据上一步的特征点计算二者的单应性矩阵。
根据可以计算出单应性矩阵的点和所有的光流特征点的比例0.33, 则是判断汽车是运动状态。通过归一化单应性矩阵的位移判断汽车的状态。
c、这里还有一个工作,原本的逻辑是选择固定位置的点作为特征点,我这里修改了一下,改成用代码寻找特征点。
cv::goodFeaturesToTrack(imgGray, corners, 300, 0.01, 10, mask);
输入灰度图,输出是角点corners, 300是输出的最多角点数, 0.01是角点质量判断,10是欧氏距离判断(类似nms), MASK是不参于的掩码区域。这里输出的特征点实际上作为每次计算单应性的初始特征点,每次都会重新更新。
到了这一步骤后,整个KIL的过程算是完成了
3、这步主要获取底盘数据,通过前后帧挡位、静止状态位(轮速传感器、IMU等)、车速等信息判断车辆的静止状态。通过光流法和底盘信息协同判断汽车的状态,分为三种静止、运动、转弯。
前后景的筛选,这里主要用了两种前景分割算法,第一种是MOG2;第二种是VIBE算法
MOG2算法,首先默认设置,也就是汽车一直处于一种状态的时候使用。
pMOG2 = cv::createBackgroundSubtractorMOG2(100, 25, false); // 默认 100 帧历史,25 阈值,false 表示不开启阴影检测
pMOG2->setVarThreshold(25.0);
pMOG2->setHistory(int(100));
MOG2其核心思想是:用概率模型去“学习”每一个像素点的历史变化,从而区分什么是背景,什么是运动前景。
高斯分布有三个关键值,均值(记忆中的颜色),方差(允许活动的范围),权重(这个权重的可靠度)。这里每个像素点最多有5个分布。
所以接口中的100的意思就是,大概经过100帧之后才会把新物体固定成背景,25表示的是方差阈值,也就是varthreshold
其次,会根据前后帧状态的变化,设定不同的参数,这里不贴具体的参数了。
pMOG2->apply(frameGray, fgMask); 更新成二值化背景图,然后通过开闭运算去除背景噪音点,获得最终的效果。
VIBE算法:它为每个像素点存储了一个样本库(Sample Set) 。当你判断一个新像素是否为背景时,直接去样本库里“比对”,如果长得像的样本够多,你就是背景。
分三种考虑啊,第一种剧烈状态进入平稳期,第二种是持续剧烈运动中;第三种则是其他可能
第一部分代码的核心:补偿机制(类似透明底盘),将底盘区域置黑,不要进行干扰。这里主要考虑的是汽车运动的状态。
第二部分则是自己实现的VIBE算法,a、单帧初始化,将原始BEV图中随机8邻域缓存在样本库中;b、判断当前的像素与样本库的距离是否符合阈值,当匹配的次数大于设定的阈值时候,该像素则为背景,芣则为前景像素,但是当连续50帧时候则更新为背景因素。c、更新样本库,分为两次更新,第一次是时间上,直接替换,第二次是空间上,替换相邻像素的样本库。
最后,将两者算法得到的前景进行融合,如果车辆是静止的,要进行阴影去除算法,得到最终的结果。然后通过一些开闭的图像处理算法进行去除噪音点。
4、检测功能
a、首先会把上一步骤的各种小模块进行合并。主要通过欧式距离合并,只考虑合并大框和小框。
b、NMS操作,过滤噪音目标。
5、目标匹配与kalman 追踪
卡尔曼滤波器使用7维状态向量 [x, y, s, r, vx, vy, vs]:
• x, y:边界框中心坐标
• s:尺度(面积 = width × height)
• r:宽高比(aspect ratio = width / height)
• vx, vy, vs:x、y方向和尺度的速度
观察量是:矩形框的对角点。
总结
目前的显示效果是如下图所示,可以看到行人走到某个区域,某个区域进行报警。归根到底,这里实际上就是分为几个步骤,1、通过光流法判断汽车的状态;2、通过MOG2和VIBE算法进行前景提取;3、对前景进行框取,通过匈牙利匹配算法和CV运动kalman 算法进行追踪平滑;4、通过前景的结果进行报警。