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

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

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

目录

1. 概述

泊松融合是图像融合处理效果最好的算法,其来自于2004年Siggraph的经典paper:《Poisson Image Editing》。以这篇文章为发端,很多大神提出了一系列的优化算法。2009年, Zeev Farbman 在的SIGGRAPH上面提出的基于Mean-Value Coordinates方法的泊松融合加速算法《Coordinates for Instant Image Cloning》(文献二)。在这篇文章中,泊松方程被转换成拉普拉斯方程,并且提出了用均值坐标Mean-Value Coordinates来近似求解这个方程,从而达到实时运算的效果。

初步了解了一下原生的泊松融合算法和均值坐标融合算法,其原理包含的内涵十分丰富,包含一些诸如列散度、拉普拉斯算子、梯度场、泊松方程等等数学知识,要完全弄明白确实需要一定的基础。这里就重点关注一下根据《Coordinates for Instant Image Cloning》(文献二)实现图像融合的过程,有机会的话再详细推导一下其原理。

2. 实现

2.1. 准备

在OpenCV中,已经收录了泊松融合算法,也就是函数seamlessClone():

这个算法要求输入一个源图像,一个目标图像,源图像希望融合到目标图像的位置,以及一个mask图像。这个mask图像也就是一张二值化图像,用来标识图像的ROI(region of interest感兴趣区域)。均值坐标融合算法的输入参数也是一样的,不过mask图像很难以处理,OpenCV自带的GUI难以满足需求。所以我这里通过QT来做GUI,通过OpenCV将图像显示到QT窗体上,然后再QT窗体的图像区域内绘制多边形,多边形内部即为ROI。可以参考我的这两篇文章:

《使用QT显示OpenCV读取的图片》

《使用QT绘制一个多边形》

2.2. 核心

2.2.1. 均值坐标(Mean-Value Coordinates)

在论文中提出了一个很重要的概念也就是均值坐标(Mean-Value Coordinates)。对于如下多边形内部的点:

都有一系列与多边形边界相关的坐标值:

也就是说,只要确定了ROI,也就确定了ROI区域内每个点的均值坐标(Mean-Value Coordinates),每个点会有m个值(m为ROI边界多边形的顶点)。

2.2.2. ROI边界栅格化

论文中是以ROI边界多边形为例的,实际用到图像处理中是不会只用几个多边形的节点来计算的,而应该是ROI边界上连续的点。实际上不用想也知道,图像融合最关键的部分就是ROI边界部分的像素值。必须要用到ROI边界上所有的像素值来计算。

也就是说这里还需要一个工作,就是将ROI边界多边形栅格化,取得其上连续的像素位置,得到准确的栅格化多边形边界。这里可以参看我的这篇文章《矢量线的一种栅格化算法》。按照顺序逐条将多边形的边栅格化,即可以得到ROI的栅格化多边形边界。

2.2.3. 核心实现

论文给出的算法伪代码如下:

这段算法描述并不复杂,转换成自然语言如下:

  1. 假设ROI区域内有n个点,其边界由m个点组成。
  2. 那么可以求每个点的MVC(均值坐标),每个点有m个坐标值,一共有n个点,MVC就是就是一个n*m的矩阵。
  3. 求ROI区域边界的像素差diff,显然其是一个m*1的矩阵。
  4. 那么新图像ROI区域的插值为:r = MVC * diff,矩阵乘法后r为n*1矩阵。
  5. 将插值r与原图像g矩阵相加:f = g + r,替换目标图像相应位置的值。

核心部分具体的实现代码如下:

QTime startTime = QTime::currentTime();
    //Step1:找到边界上所有的像素点
    vector<Vector2d> ROIBoundPointList;
    CalBoundPoint(ROIBoundPointList);
    //Step2:计算范围内每个点的 mean-value coordinates
    size_t srcImgBufNum = static_cast<size_t>(srcImg.cols) * static_cast<size_t>(srcImg.rows);
    vector<vector<double>> MVC(srcImgBufNum);
    for(size_t i = 0; i < srcImgBufNum; i++)
    {
        MVC[i].resize(ROIBoundPointList.size()-1, 0);
    }
    vector<bool> clipMap(srcImgBufNum, true);           //标识范围内的点
    cout<<"开始计算 mean-value coordinates..." << endl;
    #pragma omp parallel for        //开启OpenMP并行加速
    for (int ri = 0; ri < srcImg.rows; ++ri)
    {
        for (int ci = 0; ci < srcImg.cols; ++ci)
        {
            //点是否在多边形内
            size_t m = static_cast<size_t>(srcImg.cols) * ri + ci;
            if(!Point_In_Polygon_2D(ci, ri, ROIBoundPointList))
            {
                clipMap[m] = false;
                continue;
            }
            //逐点计算MVC
            Vector2d P(ci, ri);
            vector<double> alphaAngle(ROIBoundPointList.size());
            for(size_t pi = 1; pi < ROIBoundPointList.size(); pi++)
            {
                alphaAngle[pi] = threePointCalAngle(ROIBoundPointList[pi-1], P, ROIBoundPointList[pi]);
            }
            alphaAngle[0] = alphaAngle[ROIBoundPointList.size()-1];
            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] - P).Mod();
                MVC[m][pi-1] = w_a / w_b;
                if(_isnan(MVC[m][pi-1])==1)
                {
                    MVC[m][pi-1] = 0;
                }
            }
            double sum = 0;
            for(size_t pi = 0; pi < MVC[m].size(); pi++)
            {
                sum = sum + MVC[m][pi];
            }
            for(size_t pi = 0; pi < MVC[m].size(); pi++)
            {
                MVC[m][pi] = MVC[m][pi] / sum;
            }
        }
    }
    cout<<"计算完成!" << endl;
    //Step3:计算边界的像素插值
    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);
        }
        clipMap[l] = false;         //在多边形边上的点没法计算MVC
    }
    //Step4:插值计算
    cout<<"开始插值计算..." << endl;
    //Mat rMat(srcImg.rows, srcImg.cols, CV_64FC3);
    #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])
            {
                continue;
            }
            vector<double> r(winBandNum, 0);
            for(size_t pi = 0; pi < MVC[l].size(); pi++)
            {
                for(int bi = 0; bi < winBandNum; bi++)
                {
                    r[bi] = r[bi] + MVC[l][pi] * diff[pi * winBandNum + bi];
                }
            }
            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);
            }
        }
    }
    cout<<"插值完成!" << endl;
    QTime stopTime = QTime::currentTime();
    int elapsed = startTime.msecsTo(stopTime);
    cout<<"总结完成用时"<<elapsed<<"毫秒";

2.2.4. 实现中的问题

  1. ROI边界上的点无法计算MVC值,需要予以剔除,否则ROI边界上会出现一圈白色的点。
  2. 用到了OpenMP加速,可以大幅提高性能。如有必要的话,可以通过显卡加速。

3. 效果

3.1. 使用过程

程序源代码可参见文章最末的链接,是一个OpenCV结合QT的GUI的程序。编译运行后,点击"打开"按钮,界面会显示源图像:

点击"绘制"按钮,在源图像区域内绘制一个多边形,确定一个ROI:

准备一张想要融合的目标图像:

点击"融合"按钮,会加载目标图像,并会根据设置的位置,将源图像的ROI融合到目标图像中:

3.2. 效率

在Debug模式,不使用OpenMP加速的情况下,这个算法的效率大约需要50秒左右的时间。

在Debug模式,使用OpenMP加速,算法的效率可以优化到10秒,也就是不使用OpenMP加速时的5倍左右。而我使用的机器CPU是i7-8750H标压6核CPU,考虑到一些IO操作造成的性能损耗,这个优化效率是正常的。

最后在使用Release模式,使用OpenMP加速之后,算法的效率可以优化到1秒左右,这说明编译器优化对程序性能也是有很大影响的,尤其是对并行程序而言。

这个实现只是这个算法的初始实现,效率就已经达到了1秒左右,看来论文说的可以达到实时融合确实不是虚言。有机会再尝试一下论文中提到的一些性能优化实现。

4. 参考

[1] 泊松融合及其优化算法

[2] Coordinates for Instant Image Cloning

[3] 图像处理(十二)图像融合(1)Seamless cloning泊松克隆-Siggraph 2004

[4] 多尺度并行坐标插值实时图像克隆算法

实现代码

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

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



相关文章
|
12天前
|
机器学习/深度学习 人工智能 自然语言处理
【MM2024】阿里云 PAI 团队图像编辑算法论文入选 MM2024
阿里云人工智能平台 PAI 团队发表的图像编辑算法论文在 MM2024 上正式亮相发表。ACM MM(ACM国际多媒体会议)是国际多媒体领域的顶级会议,旨在为研究人员、工程师和行业专家提供一个交流平台,以展示在多媒体领域的最新研究成果、技术进展和应用案例。其主题涵盖了图像处理、视频分析、音频处理、社交媒体和多媒体系统等广泛领域。此次入选标志着阿里云人工智能平台 PAI 在图像编辑算法方面的研究获得了学术界的充分认可。
【MM2024】阿里云 PAI 团队图像编辑算法论文入选 MM2024
|
11天前
|
机器学习/深度学习 人工智能 算法
【MM2024】面向 StableDiffusion 的多目标图像编辑算法 VICTORIA
阿里云人工智能平台 PAI 团队与华南理工大学合作在国际多媒体顶级会议 ACM MM2024 上发表 VICTORIA 算法,这是一种面向 StableDiffusion 的多目标图像编辑算法。VICTORIA 通过文本依存关系来修正图像编辑过程中的交叉注意力图,从而确保关系对象的一致性,支持用户通过修改描述性提示一次性编辑多个目标。
|
19天前
|
算法 数据安全/隐私保护
织物图像的配准和拼接算法的MATLAB仿真,对比SIFT,SURF以及KAZE
本项目展示了织物瑕疵检测中的图像拼接技术,使用SIFT、SURF和KAZE三种算法。通过MATLAB2022a实现图像匹配、配准和拼接,最终检测并分类织物瑕疵。SIFT算法在不同尺度和旋转下保持不变性;SURF算法提高速度并保持鲁棒性;KAZE算法使用非线性扩散滤波器构建尺度空间,提供更先进的特征描述。展示视频无水印,代码含注释及操作步骤。
|
1月前
|
算法 数据可视化 数据安全/隐私保护
基于LK光流提取算法的图像序列晃动程度计算matlab仿真
该算法基于Lucas-Kanade光流方法,用于计算图像序列的晃动程度。通过计算相邻帧间的光流场并定义晃动程度指标(如RMS),可量化图像晃动。此版本适用于Matlab 2022a,提供详细中文注释与操作视频。完整代码无水印。
|
3月前
|
机器学习/深度学习 编解码 监控
算法金 | 深度学习图像增强方法总结
**图像增强技术概括** 图像增强聚焦于提升视觉效果和细节,广泛应用于医学、遥感等领域。空间域增强包括直方图均衡化(增强对比度)、对比度拉伸、灰度变换、平滑滤波(均值、中值)和锐化滤波(拉普拉斯、高通)。频率域增强利用傅里叶变换、小波变换,通过高频和低频滤波增强图像特征。现代方法涉及超分辨率重建、深度学习去噪(如CNN、Autoencoder)、图像修复(如GAN)和GANs驱动的多种图像处理任务。
105 14
算法金 | 深度学习图像增强方法总结
|
2月前
|
数据采集 资源调度 算法
【数据挖掘】十大算法之K-Means K均值聚类算法
K-Means聚类算法的基本介绍,包括算法步骤、损失函数、优缺点分析以及如何优化和改进算法的方法,还提到了几种改进的K-Means算法,如K-Means++和ISODATA算法。
96 4
|
4月前
|
机器学习/深度学习 算法 数据挖掘
算法金 | K-均值、层次、DBSCAN聚类方法解析
**摘要:** 这篇文章介绍了聚类分析的基本概念和几种主要的聚类算法。聚类是无监督学习中用于发现数据内在结构的技术,常用于市场分析、图像分割等场景。K-均值是一种基于划分的算法,简单高效但易受初始值影响;层次聚类包括凝聚和分裂方式,形成层次结构但计算复杂;DBSCAN基于密度,能处理任意形状的簇,但参数选择敏感。文章还讨论了这些算法的优缺点和适用场景,并提供了相关资源链接和Python实现。
91 9
算法金 | K-均值、层次、DBSCAN聚类方法解析
|
2月前
|
算法 前端开发 计算机视觉
基于均值坐标(Mean-Value Coordinates)的图像融合算法的优化实现
基于均值坐标(Mean-Value Coordinates)的图像融合算法的优化实现
36 0
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
|
3月前
|
算法
基于粒子群优化的图像融合算法matlab仿真
这是一个基于粒子群优化(PSO)的图像融合算法,旨在将彩色模糊图像与清晰灰度图像融合成彩色清晰图像。在MATLAB2022a中测试,算法通过PSO求解最优融合权值参数,经过多次迭代更新粒子速度和位置,以优化融合效果。核心代码展示了PSO的迭代过程及融合策略。最终,使用加权平均法融合图像,其中权重由PSO计算得出。该算法体现了PSO在图像融合领域的高效性和融合质量。

热门文章

最新文章