基于APAP算法的图像和视频拼接

一、APAP算法优点

APAP算法是结合3d投影去做的极致算法,有利于和3d融合的技术

二、APAP 算法关键

APAP 算法叫做As-Projective-As-Possible,包含了柱面投影,球面投影,特征提取,特征匹配,单应性矩阵估计,APAP变换,图像融合等核心算法,前期必须用多种不同的投影算法解决非直线相机的问题,对于监控图像来说,最大的问题就是桶形畸变和鱼眼畸变,在拼接上难度比较大,很多系统直接经过畸变矫正以后再拼接,实际上矫正以后的图像非常难拼接,矫正图像的视差比不矫正更大,所以又必须使用各种投影算法去解决视差问题。APAP算法本身是一种后处理,第一步就是需要做预处理,也就是投影矫正,做好再开始做APAP算法。这方面包含多种矫正算法,尤其是球面投影矫正。

柱面和球面矫正需要用到的工具有很多, 目前有两种方法:

  1. 3d建模,将顶点和纹理映射
  2. 在2d平面上去做3d数据公式的计算,再返回来投影到2d上

讲述这两个方法的好处和缺点,1 3d建模可以解决直观的问题,效率高,使用者必须熟悉掌握3d的核心知识, 2 使用2d做3d数据计算,这样可以解决不用3d建模的步骤,但是不直观 ,我们采用后者的方法,这样做的好处是:

  • 1 节省学习3d建模的时间
  • 2 先掌握基础数学建模 ,后期再3d建模
  • 3 3d建模投影后取平面投影的时间
  • 4 跳过复杂阶段先进入核心问题

1 柱面矫正

柱面矫正包含两个算法,

a)柱面内壁投影

b) 投影变换,八字倾斜矫正

2 球面矫正

a) 球面内壁投影

b) 双投影变换,倾斜矫正

3 球面

1 特征提取与匹配:使用 SIFT 算法提取特征点并进行匹配

使用SIFT特征和kNN匹配,通过Lowe's比率测试筛选优质匹配点。

2 全局单应性计算 计算全局单应性矩阵 g_H

这一步和普通拼接算法一样,使用RANSAC 拟合全局单应性矩阵,在这之前还需要使用更多的计算让图像变为直线相机的图像,然后做投影算法,让图像符合可以拼接,也就是说,如果我们的图像不符合拼接,那后面的局部单应性计算就没有用。其中会有两种投影算法我们必须掌握,一种就是柱面投影,一种就是球面投影算法。

3 APAP 局部单应性计算

APAP算法中,局部单应性优化是核心步骤,其能量函数需同时满足全局一致性和局部平滑性,具体做法是将图像划分为网格,为每个网格点计算局部单应性矩阵,数学计算使用以下公式:

∣∣H i −H global ∣∣2||H~i~ - H~global~||^2∣∣H i −H global ∣∣2 代表的是全局一致性,强制Hi接近全局单应Hglobal,而∣∣H i −H j ∣∣2||H~i~ - H~j~||^2∣∣H i −H j ∣∣2 代表着局部平滑,要求得极值,

则对函数求导

4 图像变形与融合:

基于局部单应性矩阵对图像进行变形,并进行线性融合,做法是将图像划分为网格,对每个网格顶点优化局部单应性Hlocal,平衡全局一致性和局部对齐,实现能量函数最小化,这里面还有一个关键的地方是图像是多头做,还是单头做,如果做单头,视差大的图像可能矫正拉伸变形严重,不大的情况就应该单头做

5 拼接点刚性变换,纹理融合

使用三维的顶点和纹理拖拽,这一步也是必须有的,但是自动化比较难,必须有手动的辅助,完全手动拉伸则耗费精力,做法应该是点击增加对应的可选点,增加纹理顶点细分,当然,这样做肯定要增加计算量了,所有顶点也必须重新划分。最简单的做法就是顶点确定,点击对应顶点,让已经存在的顶点进行位置变换。

6 多频段融合

MultiBandBlender消除拼接缝

​二、 数学推导(最小二乘问题)​

将单应性矩阵 Hi 展开为9维向量, 由于能量函数为:

对每个 h i求导,令导数为零,得到线性方程组:
(1+λ∣N(i)∣)h i −λ∑i=N(i)n∣∣hi−hj∣∣2(1+λ|N(i)|) h~i~ - λ \sum_{i=N(i)}^{n} ||h_i-h_j||^2 (1+λ∣N(i)∣)h i −λi=N(i)∑n∣∣hi−hj∣∣2

将所有网格顶点的方程联立,构建稀疏线性系统 AH=b,其中:

A 是系数矩阵(稀疏对称正定)。

H 是所有 hi​ 的拼接向量。

b 是右侧常数项(与 hglobal 相关)

三、分步骤求解

我们使用最基本的线性方程求解,这个方程为 AX + b = 0,那么这里的未知就是X,实际上就是所有临近域的单应性矩阵h

(1) 单应性矩阵向量化

c 复制代码
Mat flattenHomography(const Mat& H) {
    return H.reshape(1, 9).clone(); // 3x3 -> 9x1
}

(2) 构建稀疏线性系统

使用Eigen库(高效稀疏矩阵运算):

c 复制代码
#include <Eigen/Sparse>

void buildLinearSystem(const vector<Point2f>& gridVertices, 
                       const Mat& H_global, double lambda,
                       Eigen::SparseMatrix<double>& A, 
                       Eigen::VectorXd& b) {
    int n = gridVertices.size();
    A.resize(9 * n, 9 * n);
    b.resize(9 * n);

    // 全局单应性向量
    Mat h_global = flattenHomography(H_global);
    Eigen::Map<Eigen::VectorXd> h_global_eigen(h_global.ptr<double>(), 9);

    // 填充A和b
    for (int i = 0; i < n; i++) {
        // 第一项:H_i = H_global
        for (int k = 0; k < 9; k++) {
            A.coeffRef(9 * i + k, 9 * i + k) += 1.0;
            b(9 * i + k) = h_global_eigen(k);
        }

        // 第二项:相邻约束 (简化版:4邻域)
        vector<int> neighbors = getNeighbors(i, gridVertices);
        for (int j : neighbors) {
            for (int k = 0; k < 9; k++) {
                A.coeffRef(9 * i + k, 9 * i + k) += lambda;
                A.coeffRef(9 * i + k, 9 * j + k) -= lambda;
            }
        }
    }
}

​(3) 求解线性系统​

使用Eigen的共轭梯度法(适合稀疏矩阵),注意以下中有伪代码

c 复制代码
vector<Mat> solveLocalHomographies(const Eigen::SparseMatrix<double>& A,
                                   const Eigen::VectorXd& b, int n) {
    Eigen::ConjugateGradient<Eigen::SparseMatrix<double>> solver;
    solver.compute(A);
    Eigen::VectorXd h = solver.solve(b);

    // 将解转换为单应性矩阵列表
    vector<Mat> H_locals(n);
    for (int i = 0; i < n; i++) {
        Mat Hi(3, 3, CV_64F, h.data() + 9 * i);
        //注意伪代码,这里需要真实计算
        H_locals[i] = Hi.clone();
    }
    return H_locals;
}

​​(4) 整合到APAP类中

c 复制代码
vector<Mat> optimizeAllHomographies(const vector<Point2f>& gridVertices,
                                    const Mat& H_global, double lambda) {
    Eigen::SparseMatrix<double> A;
    Eigen::VectorXd b;
    buildLinearSystem(gridVertices, H_global, lambda, A, b);
    return solveLocalHomographies(A, b, gridVertices.size());
}

四、算法实现

主要思想流程如下:

c 复制代码
 Mat stitch(const Mat& img1, const Mat& img2) {
        // Step 1: 特征提取与匹配
        vector<KeyPoint> kp1, kp2;
        Mat desc1, desc2;
        vector<DMatch> matches;
        extractAndMatch(img1, img2, kp1, kp2, desc1, desc2, matches);

        // Step 2: 计算全局单应性
        Mat H_global = findGlobalHomography(kp1, kp2, matches);

        // Step 3: 网格划分与局部单应性优化
        Mat warped;
        localWarp(img1, img2, H_global, kp1, kp2, matches, warped);

        // Step 4: 图像融合
        Mat result;
        blendImages(warped, img2, result);
        return result;
    }

localwrap

c 复制代码
void APAPStitcher::localWarp(const Mat& img1, const Mat& img2, const Mat& H_global,
                            const vector<KeyPoint>& kp1, const vector<KeyPoint>& kp2,
                            const vector<DMatch>& matches, Mat& warped) {
    // 初始化网格顶点
    vector<Point2f> gridVertices = createGridVertices(img1.size());

    // 优化所有局部单应性
    vector<Mat> H_locals = optimizeAllHomographies(gridVertices, H_global, lambda);

    // 应用网格变形
    applyMeshWarp(img1, gridVertices, H_locals, warped);
}

APAP算法 如何适应大模型代理

且听下回分解

相关推荐
老鼠只爱大米2 小时前
LeetCode算法题详解 3:无重复字符的最长子串
算法·leetcode·面试题·滑动窗口·无重复字符的最长子串·最长子串
紫色的路2 小时前
TCP消息边界处理的精妙算法
c++·网络协议·tcp/ip·算法
知乎的哥廷根数学学派2 小时前
基于高阶统计量引导的小波自适应块阈值地震信号降噪算法(MATLAB)
网络·人工智能·pytorch·深度学习·算法·机器学习·matlab
cici158742 小时前
基于光流场的Demons算法MATLAB实现
人工智能·算法·matlab
ADI_OP2 小时前
ADAU1452的开发教程4:常规音频算法的开发(3)
算法·音视频·dsp开发·adi dsp中文资料·adi音频dsp·adi dsp开发教程
持续学习的程序员+12 小时前
部分离线强化学习相关的算法总结(td3+bc/conrft)
算法
Rui_Freely2 小时前
Vins-Fusion之 SFM 滑窗内相机位姿及特征点3D估计(十三)
人工智能·算法·计算机视觉
李泽辉_2 小时前
深度学习算法学习(六):深度学习-处理文本:神经网络处理文本、Embedding层
深度学习·学习·算法
Codeking__2 小时前
Redis的value类型及编码方式介绍——hash
redis·算法·哈希算法