基于均值坐标(Mean-Value Coordinates)的图像融合算法的优化实现

简介: 基于均值坐标(Mean-Value Coordinates)的图像融合算法的优化实现

基于均值坐标(Mean-Value Coordinates)的图像融合算法的优化实现

目录

1. 概述

我在之前的文章《基于均值坐标(Mean-Value Coordinates)的图像融合算法的具体实现》中,根据《Coordinates for Instant Image Cloning》这篇论文,详细论述了图像融合中泊松融合算法的优化算法——均值坐标(Mean-Value Coordinates)融合算法的具体实现。其实在这篇论文中,还提出了两种优化实现,能够进一步提升效率,这里就论述一下其优化算法的具体实现。

2. 实现

2.1. 原理

均值坐标融合算法的核心思想是算出ROI中每个点的MVC(Mean-Value Coordinates),如果ROI中存在n个点,ROI边界像素为m个点,那么该算法的时间复杂度至少为O(nm)。根据《Coordinates for Instant Image Cloning》的描述,MVC融合算法修正值其实是一个线性区间,只要得到其中一些关键点的融合修正值,其他点的融合修正值就可以根据周围的融合修正值线性插值出来。

因此,可以通过CGAL来对ROI多边形边界构建一个自适应三角网,以边界上每个栅格点作为约束构网,为了满足Delaunay特性,就会在ROI内部新添加一些点,这样就会出现边界小而密集,边界大而稀疏的自适应三角网(可参看这篇文章《通过CGAL将一个多边形剖分成Delaunay三角网》):

这样,n个点就会将为常数级别个数c,也就是时间复杂度至少为O(cm)。当然从三角面上插值也会有时间消耗,但时间复杂度会明显小于计算均值坐标。

2.2. 核心代码

具体核心代码实现如下(完整的代码实现地址见文章末尾):

//三角网优化
void QImageShowWidget::MVCBlendOptimize(int posX, int posY)
{
    QTime startTime = QTime::currentTime();
    //Step1:找到边界上所有的像素点
    vector<Vector2d> ROIBoundPointList;
    CalBoundPoint(ROIBoundPointList);
    //
    CDT cdt;
    vector<Vertex_handle> vertexList;    
    for(int i = 0; i<ROIBoundPointList.size(); i++)
    {
        //cout<<ROIBoundPointList[i].x<<','<<ROIBoundPointList[i].y<<'\t';
        //vertexList.push_back(cdt.insert(Point(pointList[i].x(), pointList[i].y() )));
        vertexList.push_back(cdt.insert(CDTPoint(ROIBoundPointList[i].x, ROIBoundPointList[i].y )));
    }
    for(unsigned int i =0;i<vertexList.size()-1;i++)
    {
        cdt.insert_constraint(vertexList[i],vertexList[i+1]);
    }
    std::cout << "Number of vertices: " << cdt.number_of_vertices() <<std::endl;
    std::cout << "Meshing the triangulation..." << std::endl;
    CGAL::refine_Delaunay_mesh_2(cdt, Criteria());
    std::cout << "Number of vertices: " << cdt.number_of_vertices() <<std::endl;
    vector<Vector2d> vertex_list;
    map<Vector2d, size_t> vertex_map;
    for(CDT::Vertex_iterator vit = cdt.vertices_begin(); vit!= cdt.vertices_end(); ++vit)
    {
        vertex_map.insert(make_pair(Vector2d(vit->point().x(), vit->point().y()), vertex_list.size()));
        vertex_list.push_back(Vector2d(vit->point().x(), vit->point().y()));
    }
    //计算边界的像素差值
    vector<int> diff;
    for(size_t i = 0; i < ROIBoundPointList.size()-1; i++)
    {
        //size_t l = (size_t) srcImg.cols * ROIBoundPointList[i].y + ROIBoundPointList[i].x;
        for(int bi = 0; bi < winBandNum; bi++)
        {
            size_t m = (size_t) dstImg.cols * winBandNum * (ROIBoundPointList[i].y + posY)+ winBandNum * (ROIBoundPointList[i].x + posX) + bi;
            size_t n = (size_t) srcImg.cols * winBandNum * ROIBoundPointList[i].y + winBandNum * ROIBoundPointList[i].x + bi;
            int d = (int)(dstImg.data[m]) - (int)(srcImg.data[n]);
            diff.push_back(d);
            //rMat.data[n] = d;
        }
        //clipMap[l] = false;         //在多边形边上的点没法计算MVC
    }
    cout<<"开始计算 mean-value coordinates..." << endl;
    vector<Vec3d> tri_mesh_vertex_R(vertex_list.size());
    #pragma omp parallel for        //开启OpenMP并行加速
    for (int vi = 0; vi < vertex_list.size(); ++vi)
    {
        //逐点计算MVC
        vector<double> alphaAngle(ROIBoundPointList.size());
        for(size_t pi = 1; pi < ROIBoundPointList.size(); pi++)
        {
            alphaAngle[pi] = threePointCalAngle(ROIBoundPointList[pi-1], vertex_list[vi], ROIBoundPointList[pi]);
        }
        alphaAngle[0] = alphaAngle[ROIBoundPointList.size()-1];
        vector<double> MVC(ROIBoundPointList.size()-1, 0);
        for(size_t pi = 1; pi < ROIBoundPointList.size(); pi++)
        {
            double w_a = tan(alphaAngle[pi-1]/2) + tan(alphaAngle[pi]/2);
            double w_b = (ROIBoundPointList[pi-1] - vertex_list[vi]).Mod();
            MVC[pi-1] = w_a / w_b;
            if(_isnan(MVC[pi-1])==1)
            {
                MVC[pi-1] = 0;
            }
        }
        double sum = 0;
        for(size_t pi = 0; pi < MVC.size(); pi++)
        {
            sum = sum + MVC[pi];
        }
        for(size_t pi = 0; pi < MVC.size(); pi++)
        {
            MVC[pi] = MVC[pi] / sum;
        }
        Vec3d r(0.0,0.0,0.0);
        for(size_t pi = 0; pi < MVC.size(); pi++)
        {
            for(int bi = 0; bi < winBandNum; bi++)
            {
                r[bi] = r[bi] + MVC[pi] * diff[pi * winBandNum + bi];
            }
        }
        tri_mesh_vertex_R[vi] = r;
    }
    cout<<"计算完成!" << endl;
    //遍历每一个三角面
    vector<vector<size_t>> face_vertex_index;
    CDT::Face_iterator fit;
    for (fit = cdt.faces_begin(); fit!= cdt.faces_end(); ++fit)
    {
        vector<size_t> index(3);
        for(int i = 0; i<3; i++)
        {
            auto iter = vertex_map.find(Vector2d(fit->vertex(i)->point().x(), fit->vertex(i)->point().y()));
            if(iter == vertex_map.end())
            {
                continue;
            }
            index[i] = iter->second;
        }
        face_vertex_index.push_back(index);
    }
    size_t srcImgBufNum = static_cast<size_t>(srcImg.cols) * static_cast<size_t>(srcImg.rows);
    vector<size_t> clipMap(srcImgBufNum, 0);           //标识范围内的点: 0标识初始不能写入,1以上标识在那个三角形
    #pragma omp parallel for        //开启OpenMP并行加速
    for(int fi = 0; fi < face_vertex_index.size(); fi++)
    {
        Vector2d v0 = vertex_list[face_vertex_index[fi][0]];
        Vector2d v1 = vertex_list[face_vertex_index[fi][1]];
        Vector2d v2 = vertex_list[face_vertex_index[fi][2]];
        double minX = std::min(std::min(v0.x, v1.x), v2.x);
        double minY = std::min(std::min(v0.y, v1.y), v2.y);
        double maxX = std::max(std::max(v0.x, v1.x), v2.x);
        double maxY = std::max(std::max(v0.y, v1.y), v2.y);
        int sX = std::max(int(floor(minX)), 0);
        int sY = std::max(int(floor(minY)), 0);
        int eX = std::max(int(ceil(maxX)), srcImg.cols - 1);
        int eY = std::max(int(ceil(maxY)), srcImg.rows - 1);
        for(int yi = sY; yi <= eY; yi++)
        {
            for(int xi = sX; xi <= eX; xi++)
            {
                if(PointinTriangle(Vector3d(v0), Vector3d(v1), Vector3d(v2), Vector3d(xi, yi, 0)))
                {
                    size_t m = static_cast<size_t>(srcImg.cols) * static_cast<size_t>(yi) + xi;
                    clipMap[m] = fi+1;
                }
            }
        }
    }
    cout<<"开始插值计算..." << endl;
    //Mat result(srcImg.rows, srcImg.cols, CV_8UC1);
    #pragma omp parallel for
    for (int ri = 0; ri < srcImg.rows; ++ri)
    {
        for (int ci = 0; ci < srcImg.cols; ++ci)
        {
            size_t l = (size_t) srcImg.cols * ri + ci;
            if(clipMap[l] == 0)
            {
                continue;
            }
            if(!Point_In_Polygon_2D(ci, ri, ROIBoundPointList))
            {
                continue;
            }
            size_t fi = clipMap[l]-1;
            size_t index0 = face_vertex_index[fi][0];
            size_t index1 = face_vertex_index[fi][1];
            size_t index2 = face_vertex_index[fi][2];
            vector<double> r(winBandNum, 0);
            for(int bi = 0; bi < winBandNum; bi++)
            {
                Vector3d p0(vertex_list[index0].x, vertex_list[index0].y, tri_mesh_vertex_R[index0][bi]);
                Vector3d p1(vertex_list[index1].x, vertex_list[index1].y, tri_mesh_vertex_R[index1][bi]);
                Vector3d p2(vertex_list[index2].x, vertex_list[index2].y, tri_mesh_vertex_R[index2][bi]);
                Vector3d vp(ci, ri, 0);
                CalPlanePointZ(p0, p1, p2, vp);
                r[bi] = vp.z;
            }
            for(int bi = 0; bi < winBandNum; bi++)
            {
                size_t n = (size_t) srcImg.cols * winBandNum * ri + winBandNum * ci + bi;
                size_t m = (size_t) dstImg.cols * winBandNum * (ri + posY)+ winBandNum * (ci + posX) + bi;
                dstImg.data[m] = min(max(srcImg.data[n] + r[bi], 0.0), 255.0);
            }
        }
    }
    //imwrite("D:/result.tif", result);
    cout<<"插值完成!" << endl;
    QTime stopTime = QTime::currentTime();
    int elapsed = startTime.msecsTo(stopTime);
    cout<<"总结完成用时"<<elapsed<<"毫秒";
}

主要思路还是通过ROI多边形栅格建立三角网,计算网格点的MVC,继而计算融合修正值;而其他点的融合修正值则通过所在三角形顶点的融合修正值插值得到。

注意这里麻烦的地方是还得计算每个点是在那个三角形内,我这里是采取索引数组的办法。如果直接采取遍历每个点与每个三角形的办法,那么时间复杂度可能会超过计算MVC的复杂度。而插值的算法可以参考这篇文章《已知空间三点组成的面求该面上某点的Z值》

2.3. 第二种优化

《Coordinates for Instant Image Cloning》这篇论文中,还介绍了第二种优化算法。算法思想是除了减少ROI内的点,还可以减少ROI边界上的点:每个点的MVC值其实可以不用到边界上所有的点,可以通过一种规则算法来指定需要的点。可惜这个规则算法我也没看明白,有机会再进一步研究。

3. 结果

融合的源影像:


融合的目标影像:


融合的结果:


运行的时间:

这里可以看到,优化后的融合效率为501毫秒,而优化之前的效率为1秒,效率提升了50%。

实现代码

分类: 图像处理 , 计算机视觉

标签: Mean-Value , OpenCV , 泊松融合 , 均值坐标 , 图像融合

相关文章
|
1天前
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
1月前
|
算法 数据安全/隐私保护 计算机视觉
基于Retinex算法的图像去雾matlab仿真
本项目展示了基于Retinex算法的图像去雾技术。完整程序运行效果无水印,使用Matlab2022a开发。核心代码包含详细中文注释和操作步骤视频。Retinex理论由Edwin Land提出,旨在分离图像的光照和反射分量,增强图像对比度、颜色和细节,尤其在雾天条件下表现优异,有效解决图像去雾问题。
|
4天前
|
机器学习/深度学习 存储 算法
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
近端策略优化(PPO)是深度强化学习中高效的策略优化方法,广泛应用于大语言模型的RLHF训练。PPO通过引入策略更新约束机制,平衡了更新幅度,提升了训练稳定性。其核心思想是在优势演员-评论家方法的基础上,采用裁剪和非裁剪项组成的替代目标函数,限制策略比率在[1-ϵ, 1+ϵ]区间内,防止过大的策略更新。本文详细探讨了PPO的基本原理、损失函数设计及PyTorch实现流程,提供了完整的代码示例。
97 10
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
|
1月前
|
算法 数据可视化 安全
基于DWA优化算法的机器人路径规划matlab仿真
本项目基于DWA优化算法实现机器人路径规划的MATLAB仿真,适用于动态环境下的自主导航。使用MATLAB2022A版本运行,展示路径规划和预测结果。核心代码通过散点图和轨迹图可视化路径点及预测路径。DWA算法通过定义速度空间、采样候选动作并评估其优劣(目标方向性、障碍物距离、速度一致性),实时调整机器人运动参数,确保安全避障并接近目标。
146 68
|
2月前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
206 80
|
2天前
|
传感器 算法 物联网
基于粒子群算法的网络最优节点部署优化matlab仿真
本项目基于粒子群优化(PSO)算法,实现WSN网络节点的最优部署,以最大化节点覆盖范围。使用MATLAB2022A进行开发与测试,展示了优化后的节点分布及其覆盖范围。核心代码通过定义目标函数和约束条件,利用PSO算法迭代搜索最佳节点位置,并绘制优化结果图。PSO算法灵感源于鸟群觅食行为,适用于连续和离散空间的优化问题,在通信网络、物联网等领域有广泛应用。该算法通过模拟粒子群体智慧,高效逼近最优解,提升网络性能。
|
2天前
|
机器学习/深度学习 数据采集 算法
基于GWO灰狼优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a,展示了时间序列预测算法的运行效果(无水印)。核心程序包含详细中文注释和操作视频。算法采用CNN-GRU-SAM网络,结合灰狼优化(GWO),通过卷积层提取局部特征、GRU处理长期依赖、自注意力机制捕捉全局特征,最终实现复杂非线性时间序列的高效预测。
|
20小时前
|
算法
基于SOA海鸥优化算法的三维曲面最高点搜索matlab仿真
本程序基于海鸥优化算法(SOA)进行三维曲面最高点搜索的MATLAB仿真,输出收敛曲线和搜索结果。使用MATLAB2022A版本运行,核心代码实现种群初始化、适应度计算、交叉变异等操作。SOA模拟海鸥觅食行为,通过搜索飞行、跟随飞行和掠食飞行三种策略高效探索解空间,找到全局最优解。
|
1月前
|
机器学习/深度学习 数据采集 算法
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a实现时间序列预测,采用CNN-GRU-SAM网络结构。卷积层提取局部特征,GRU层处理长期依赖,自注意力机制捕捉全局特征。完整代码含中文注释和操作视频,运行效果无水印展示。算法通过数据归一化、种群初始化、适应度计算、个体更新等步骤优化网络参数,最终输出预测结果。适用于金融市场、气象预报等领域。
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
|
1月前
|
机器学习/深度学习 人工智能 算法
机器学习算法的优化与改进:提升模型性能的策略与方法
机器学习算法的优化与改进:提升模型性能的策略与方法
260 13
机器学习算法的优化与改进:提升模型性能的策略与方法

热门文章

最新文章