一 逻辑实现
函数作用
这是一个路由函数,router function,根据配置的 correspondence_method, 选择使用哪种方法来收集对应点,correspondences, 对应点是全局运动估计的基础数据。
在全局运动估计流程中的位置。
全局运动估计的完整流程
1 收集阶段,-本函数,根据配置选择方法收集对应点
方法A,角点检测方法,correspondence from corners
方法B, MV方法,correspondence from mvs
输出:对应点数组,当前帧位置,参考帧位置。
2 合并阶段,RANSAC算法,将收集到的对应点聚合成全局运动模型
在compute+global motion中调用determine gm parames()->svt_aom_ransac()
RANSAC算法从大量对应点中找出最能代表全局运动的模型参数
输出:全局运动模型参数,放射变换矩阵等
3 应用阶段,在模式决策中使用全局运动模型为每个块计算MV
两种方法的对比:
角点方法
原理:基于图像特征,角点进行匹配,不依赖运动估计结果
优点:更鲁棒,精度高,不依赖ME质量,适合复杂运动
缺点:计算复杂度中等
适用场景:复杂运动,ME质量差时,需要高精度时
MV方法,(MV_64x64, MV_32x32, MV_16x16/MV_8x8)
原理:从运动估计结果中提取MV,转换为对应点
优点:计算速度快,利用已有的ME结果
缺点:依赖ME质量,精度受ME影响
适用场景:ME质量好时,需要快速计算时。
函数参数说明:
pcs 图像父控制集,包含`
` gm_ctrls.correspondence_method 对应点收集方法配置`
`pa_me_data: 运动估计数据MV方法需要`
`其他全局运动相关配置`
`frm_buffer 当前帧图像缓冲区,亮度分量`
`frm_width 当前帧宽度,像素`
`frm_height 当前帧高度`
`frm_stride 当前帧行跨度,字节数,用于访问图像数据`
`frm_corners 输入,当前帧已经检测的角点数组,仅角点方法使用`
`格式[x0, y0, x1, y1, x2, y2, ...]`
`在调用本函数前已经通过svt_av1_fast_corner_detect() 检测完成`
`MV方法不使用此参数`
`num_frm_corners 输入,当前帧角点数量,仅角点方法使用`
`ref 参考帧图像缓冲区,亮度分量`
`ref_stride 参考帧行跨度`
`correspondences 输出:收集到的对应点数组,每个对应点表示,当前帧位置(x,y) 参考帧位置(rx, ry)`
`这些对应点将被传递给RANSAC算法进行聚合`
`num_correspondences 输出 实际手机到的对应点数量`
`list_idx 参考帧列表索引,MV方法使用`
`0 list0 前向参考帧`
`1 list1 后向参考帧`
`ref_idx 参考帧索引,仅MV方法使用`
`在指定列表中的位置 (0,1,2,....)`
`void gm_compute_correspondence(PictureParentControlSet* pcs, uint8_t *frm_buffer, int frm_width, int frm_height, int frm_stride, int *frm_corners, int num_frm_corners, uint8_t *ref, `
`int ref_stride, `
`COrrespondence* correspondences, int* num_correspondences, uint8_t list_idx, uint8_t ref_idx)`
`{`
`//根据配置选择对应点收集方法`
`//检查 correspondence method配置,决定使用哪种方法收集对应点`
`if (pcs->gm_ctrls.correspondence_method == CORNERS) `
`{`
`//方法A,角点检测方法`
`//使用角点检测和匹配来收集对应点`
`//这是更常用和更鲁棒的方法,不依赖运动估计的质量`
`corresppondence_from_corners(`
`&pcs->gm_ctrls, //全局运动控制参数,包含角点数量配置等`
`frm_buffer, //当前帧图像缓冲区`
` frm_height, // 当前帧高度`
` frm_stride, // 当前帧行跨度`
` frm_corners, // 当前帧已检测的角点数组(输入)`
` num_frm_corners, // 当前帧角点数量(输入)`
` ref, // 参考帧图像缓冲区`
` ref_stride, // 参考帧行跨度`
` correspondences, // 输出:匹配得到的对应点数组`
` num_correspondences); // 输出:匹配成功的对应点数量`
`//角点方法的工作流程`
`//1 在参考帧中检测角点,correspondence from corners 内部完成`
`//2 匹配当前帧和参考帧的角点,通过NCC归一化互相关`
`//精炼匹配结果,提高亚像素精度`
`//4 输出高质量的对应点数组`
`} else {`
`//方法B MV方法`
`//从运动估计结果中提取MV,转换为对应点`
`//这种方法利用已有ME结果,计算速度快`
`//断言检查,确保correspondence method 最有效的MV方法`
`//MV方法包括,MV_64x64(0), MV_32x32(1), MV_16x16(2), MV_8x8(3)`
` orrespondence_from_mvs(`
` pcs, // 图像父控制集(包含ME结果数据)`
` correspondences, // 输出:从MV转换得到的对应点数组`
` num_correspondences, // 输出:收集到的对应点数量`
` list_idx, // 参考帧列表索引(0=List0, 1=List1)`
` ref_idx); // 参考帧索引(在列表中的位置)`
`}`
`//MV方法的工作流程`
`//1 遍历所有SB super block 64x64块`
`//2 从每个SB内部的子块,根据correspondence method选择块大小,提取MV`
`//3 将MV转换为对应点,当前帧位置 x,y 参考帧位置, rx = x + mv.x , ry = y + mv.y`
`//4输出对应点数组`
`}`
`/*`
`通过角点检测和匹配来收集对应点,这是角点聚合MV模式的核心函数`
`角点检测方法 vs MV方法`
`角点方法,基于图像特征,角点进行匹配,不依赖运动结果`
`MV方法,基于运动估计的MV结果,依赖ME的质量`
`角点方法通常更准确,因为角点事图像中的稳定特征点。`
`完整流程,三步`
`第一步:角点检测,在调用本函数前已完成`
`当前帧的角点已经通过svt_av1_fast_corner_detect() 检测完成`
`角点存储在frm_corners 中,数量为num_frm_corners`
`角点检测使用FAST算法,找到图像中的特征点,边缘,角落等`
`第二步:参考帧角点检测,本函数内部`
`在参考帧中检测角点,找到对应的特征点`
`使用相同的FAST角点检测算法`
`第三部:角点匹配,本函数内部`
`将当前帧的角点与参考帧的角点进行匹配`
`通过计算归一化互相关NCC找到最佳匹配`
` - 只有匹配质量超过阈值的角点对才会被保留`
` * - 匹配结果会被进一步精炼以提高精度`
`匹配过程详解 在svt_av1_determine_correspondence中`
` * 1. 对当前帧的每个角点:`
` * - 在参考帧的所有角点中搜索最佳匹配`
` * - 计算两个角点周围区域的归一化互相关(NCC)`
` * - 只考虑距离合理的候选(避免匹配到太远的点)`
` * - 选择NCC值最高的匹配`
` * 2. 匹配质量检查:`
` * - 只有当 NCC > THRESHOLD_NCC * variance 时才保留匹配`
` * - 这确保了匹配的可靠性`
` * 3. 匹配精炼(improve_correspondence):`
` * - 在匹配点周围的小窗口(SEARCH_SZ x SEARCH_SZ)内进行精细搜索`
` * - 双向精炼:先精炼参考帧位置,再精炼当前帧位置`
` * - 找到亚像素精度的最佳匹配位置`
` * 输出:`
` * - 对应点数组:每个对应点表示当前帧角点(x,y)和参考帧角点(rx,ry)的匹配`
` * - 这些对应点将被传递给RANSAC算法,聚合成全局运动模型`
` * `
` * 为什么角点方法更常用?`
` * - 角点是图像中的稳定特征,对光照变化、噪声等更鲁棒`
` * - 不依赖运动估计的质量,即使ME失败也能工作`
` * - 匹配精度高,能提供高质量的对应点`
` * - 适合处理复杂运动(旋转、缩放等)`
` * @param gm_ctrls 全局运动控制参数`
` * @param frm_buffer 当前帧图像缓冲区`
` * @param frm_width 当前帧宽度`
` * @param frm_height 当前帧高度`
` * @param frm_stride 当前帧行跨度`
` * @param frm_corners 输入:当前帧已检测的角点数组(格式:[x0,y0, x1,y1, ...])`
` * @param num_frm_corners 输入:当前帧角点数量`
` * @param ref 参考帧图像缓冲区`
` * @param ref_stride 参考帧行跨度`
` * @param correspondences 输出:匹配得到的对应点数组`
` * @param num_correspondences 输出:匹配成功的对应点数量`
`*/`
`static void correspondence_from_corners(GmControls* gm_ctrls, uint8_t* frm_buffer, int frm_width, int frm_height,`
` int frm_stride, int* frm_corners, int num_frm_corners, uint8_t* ref,`
` int ref_stride, Correspondence* correspondences, int* num_correspondences)`
`{`
`//第一步,在参考帧中检测角点,`
`/使用FAST 角点检测算法在参考帧中找到特征点`
`//角点存储格式:[x0, y0, x1, y1, x2, y2, ...],所以数组大小是 2 * MAX_CORNERS`
`int ref_corners[2 * MAX_CORNERS]; //最大4096 个角点`
`//在参考帧中检测角点,最多检测 MAX_CORNERS个`
`//角点存储格式 [x0, y0, x1, y1, x2, y2, ...] 所以数组大小事2 * MAX_CORNERS`
`//在参考帧中检测角点,最多检测MAX_CORNERS个`
`//返回实际检测到的角点数量`
`int num_ref_corners = svt_av1_fast_corner_detect(`
`(unsigned char*)ref, frm_width, frm_height, ref_stride, ref_corners, MAX_CORNERS);`
`//第二步,根据配置调整使用的角点数量`
`//gm_ctrls->corners 控制使用多少比例的角点`
`//1 使用1/4 的角点,`
`//2 使用1/2的角点`
`//使用3/4的角点`
`//使用全部的角点,`
`//这样可以平衡计算复杂度和匹配精度`
` num_ref_corners = num_ref_corners * gm_ctrls->corners / 4;`
` num_frm_corners = num_frm_corners * gm_ctrls->corners / 4;`
`//第三步,匹配当前帧和参考帧的角点,生成对应点`
`//这是核心步骤,通过归一化互相关NCC匹配角点`
`//匹配过程 在svt_av1_determine_correspondence 中实现,`
`//1 对当前帧的每个角点,在参考帧的所有角点中找到最佳匹配`
`//2计算两个角点周围match_sz x match_sz 区域的归一化互相关`
`//3保留NCC > THREASHOLD_NCC * variance 的高质量匹配`
`//4 对匹配结果进行精炼,提高亚像素精度`
`//输出:对应点数组,每个对应点表示`
`//x,y 当前帧中的角点位置`
`//rx, ry 参考帧中匹配的角点位置`
`//这些对应点奖杯传递给RANSAC算法,聚合成全局运动模型参数`
`*num_correspondences = svt_av1_determine_correspondence(frm_buffer, (int*)frm_corners`
`,` `num_frm_corners,`
`ref, `
`(int*)ref_corners,`
`num_ref_corners,`
`frm_width,`
`frm_height,`
`frm_stride,`
`ref_stride,`
`correspondences,`
`gm_ctrls->match_sz);`
`}`
`/*`
`FAST-9` `角点检测,带非极大值抑制,全局运动估计中角点检测的核心函数`
`函数作用`
`这是FAST` `Features` `from Accelerated` `Segment` `Test` `角点检测算法的完整实现,包含三个步骤,检测,评分,非极大值抑制,函数用于在全局运动估计中检测图像特征点。`
`FAST算法原理`
`FAST算法通过检查像素周围16个点的亮度差异来快速判断是否为角点,`
`如果中心像素周围有连续9个,或者更多点的亮度明显高于或者低于中心的像素,则认为是角点9` `表示需要连续9个点满足条件。FAST-9` `变体。`
`算法流程:`
`步骤1:角点检测,svt_aom_fast9_detect`
`遍历图像中的每个像素,边界除外`
`检查像素周围16个采样点的亮度`
`如果满足FAST9条件,标记为候选角点`
`输出:所有候选角点的坐标数组`
`步骤2:角点评分svt_aom_fast9_score`
`为每个候选角点计算一个分数`
`分数表示该角点的强度或显著性`
`分数越高,角点越明显,越稳定`
`输出:每个角点对于的分数数组`
`步骤3:非极大值抑制` `svt_aom_nonmax_suppression`
`在焦点密集区域,只保留分数最高的角点`
`抑制周围分数较低的角点,避免重复检测`
`输出,经过筛选的高质量角点数组`
`在全局运动估计中的作用`
`1` `在当前帧和参考帧中匹配对应点`
`2` `通过RANSAC算法拟合生成全局运动模型`
`3实现从局部特征到全局运动的聚合`
`im 输入图像缓冲区,亮度分量,8位灰度图`
`图像数据按行存储,每一行stride字节`
`xsize 图像宽度,像素数`
`ysize 图像高度,像素数`
`stride` `图像行跨度,字节数`
`通常等于图像宽度,但是可能包含对齐填充`
`用于计算像素在缓冲区中的位置im[y * stride + x]`
`b` `角点检测阈值,brightness` `threshold`
`控制角点检测的敏感度`
`值越大,检测到的角点越少,只检测非常明显的角点`
`值越小,检测到的角点越多,包括较弱的角点`
`典型值范围` `10-30`
`ret_num_corners 输出参数,返回检测到的角点数量`
`经过非极大值抑制后的最终角点数量`
`xy*` `返回角点坐标数组的指针`
`每个元素是一个xy结构体,包含角点(x,y)坐标`
`数组大小为ret_num_corners`
`调用者需要负责释放内存,使用free`
`内存管理`
`函数内部会分配内存存储角点数组`
`调用者需要在使用完成后调用free 释放返回的指针`
`函数内部会释放中间结果,corners和scores数组`
`*/`
`xy*` `svt_aom_fast9_detect_nonmax(const byte* im, `
`int xsiez, int ysize, int stride, int b, int *ret_num_corners)`
`{`
`//变量声明`
`//corners 存储第一步检测到的所有候选角点坐标`
`//类型xy是结构体,包含x和y两个整数成员`
`xy*` `corners;`
`//num_corners` `候选角点的数量,检测过程中会被更新,`
`//scores 存储每个候选角点的分数数组`
`//分数表示角点的显著性` `强度,用于后续的非极大值抑制`
`int *scores;`
`//nonmax 存储经过非极大值抑制后的最终角点坐标`
`//这是函数的返回值,包含高质量的,非重复的角点`
`xy*` `nonmax;`
`//步骤1,角点检测`
`//调用FAST-9` `检测算法,在图像中找出所有候选角点。`
`//参数说明`
`//im 输入图像缓冲区`
`//xsize,` `ysize 图像尺寸`
`//stride` `行跨度`
`//b 检测阈值`
`//&num_corners` `输出参数,返回检测的角点数量`
`//返回值,候选角点坐标数组,需要后续释放内存`
`/检测原理`
`//遍历图像中每个像素,边界3像素除外需要16个采样蒂娜`
`//检查像素周围16个采样点的亮度`
`//如果连续9个点都明显亮于,或者暗于中心像素,标记为角点。`
`corners = svt_aom_fast9_detect(im, xsize, ysize, stride, b, &num_corners);`
`//步骤2,角点评分,`
`//为每一个候选点计算一个分数,表示角点的显著性`
`//参数说明`
`//im 输入图像,用于计算分数`
`//` `stride` `行跨度`
`//corners 候选角点数组,步骤1的输出`
`//num_corners` `角点数量`
`//b` `检查阈值` `用于评分计算`
`//返回值,分数数组,每个角点对应一个分数`
`//评分原理`
`//通过二分搜索找到使该点仍然能被检测为角点的最大阈值`
`//这个阈值就是该角点的分数,`
`//分数越高,说明角点越明显,越稳定`
`scores` `= svt_aom_fast9_score(im, stride, corners, num_corners, b);`
`//步骤3,非极大值抑制`
`//在角点密集区域,只保留分数最高的角点,抑制周围的低分角点`
`//参数说明`
`//corners` `候选角点数组`
`//scores` `角点分数数组`
`//num_corners` `角点数量`
`//ret_num_corners 输出参数,返回抑制后的角点数量`
`//返回值,经过筛选的最终角点数组,需要调用者释放内存`
`//抑制原理`
`//对于每个角点,检查其3x3邻域内的其他角点`
`//如果领域内有分数更高的角点,则抑制当前角点`
`//只保留局部最大值,非极大值抑制`
`//这也可以避免在同一个特征区域监测到多个重要的角点`
`nonmax = svt_aom_nonmax_suppresion(corners, scores, num_corners, ret_num_corners);`
`//内存清理`
`//释放中间结果的内存,只保留最终的非极大值抑制结果`
`//释放候选角点数组,步骤1的输出,已被nonmax替代`
`free(corners);`
`//释放角点分数数组,(步骤2的输出,不再需要)`
`free(scores);`
`//返回值最终结果`
`//返回经过非极大值抑制后的高质量角点数组`
`//调用者需要在使用完后调用free(nonmax)释放内存`
`return nonmax;`
`}`
`最小二乘法计算线性回归。通过找到的参考帧中的角点和编码帧中的角点,`
`计算映射关系。`
`x' = a1*x + a2*y + a3`
`y' = b1*x + b2*y + b3`
`