一、图像金字塔

关于图像金字塔的介绍,这里推荐一篇毛星云写的博客 OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放,是基于《OpenCV3编程入门》中图像金字塔部分编写,基础概念信息介绍很详细。这篇文章是针对基本的图像金字塔介绍再详细描述。

图像高斯金字塔

图像高斯金字塔是对一张输入图像先模糊再下采样为原来宽高的1/2(宽高缩小一半)、不断重复模糊向下采样的过程就得到了不同分辨率的输出图像,叠加在一起就形成了图像金字塔、所以图像金字塔是图像的空间多分辨率存在形式。这里的模糊是指高斯模糊,所以这个方式生成的金字塔图像又称为高斯金字塔图像。高斯金字塔图像有两个基本操作:

1、reduce 是从原图生成高斯金字塔图像、生成一系列低分辨图像,OpenCV对应的相关API为:

pyrDown(
InputArray src,
OutputArray dst,
constSize & dstsize = Size(),
intborderType = BORDER_DEFAULT
)

其中输出的图像dst大小必须满足下面的要求:

2、expand是从高斯金字塔图像反向生成高分辨率图像,其OpenCV对应的API为:

pyrUp(
InputArray src,
OutputArray dst,
constSize & dstsize = Size(),
intborderType = BORDER_DEFAULT
)

其中输出的图像dst大小必须满足下面的要求:

拉普拉斯金字塔

对输入图像实现金字塔的reduce操作就会生成不同分辨率的图像、对这些图像进行金字塔expand操作,然后使用reduce减去expand之后的结果就会得到图像拉普拉斯金字塔图像。举例如下:

输入图像G(0)

金字塔reduce操作生成 G(1), G(2), G(3)

拉普拉斯金字塔:
L0 = G(0)-expand(G(1))
L1 = G(1)-expand(G(2))
L2 = G(2)–expand(G(3))

G(0) 减去 expand(G(1)) 得到的结果就是两次高斯模糊输出的不同,所以 L0 称为 DOG(高斯不同)、它约等于 LOG 所以又称为拉普拉斯金字塔。所以要求的图像的拉普拉斯金字塔,首先要进行金字塔的 reduce 操作,然后在通过 expand 操作,最后相减得到拉普拉斯金字塔图像。

拉普拉斯金字塔图像重建

我们从拉普拉斯金字塔的定义知道,拉普拉斯金字塔的每一层都是一个高斯分差图像(DOG),以第L0层为例:

拉普拉斯金子图 L0 层 = 原图 – expand(高斯金字塔G1层)

对上面的共识变换,得到如下的结果:

原图 = 拉普拉斯金子图 L0 层 + expand(高斯金字塔G1层)

也就是说我们可以基于低分辨率的图像与它的高斯差分图像,重建生成一个高分辨率的图像。

上图左侧是对两幅输入图像生成高斯金字塔,在最小分辨率的时候对他们进行图像融合生成一个低分辨率版本的融合图像,同时生成它们的拉普拉斯金字塔的融合图像,右侧的图像是根据低分辨率版本的融合图像以及它们的拉普拉斯差分图像,不断重建生成了最终的高分辨融合重新的近似原图。

下面是一些功能代码:

建立图像高斯金字塔并生成最小分辨率图像代码如下:vector<Mat> buildGaussianPyramid(Mat &image) {vector<Mat> pyramid;Mat copy= image.clone();pyramid.push_back(image.clone());Mat dst;for( int i = 0; i < level; i++) {pyrDown( copy, dst, Size( copy.cols / 2, copy.rows / 2));dst.copyTo( copy);pyramid.push_back(dst.clone());}smallestLevel = dst;return pyramid;
}
建立拉普拉斯金字塔并生成最小分差图像代码如下:vector<Mat> buildLapacianPyramid(Mat &image) {vector<Mat> lp;Mat temp;Mat copy= image.clone();Mat dst;for( int i = 0; i < level; i++) {pyrDown( copy, dst, Size( copy.cols / 2, copy.rows / 2));pyrUp(dst, temp, copy.size());Mat lapaian;subtract( copy, temp, lapaian);lp.push_back(lapaian);copy= dst.clone();}smallestLevel = dst;return lp;
}
实现对每一层融合生成新图的代码如下:
a :原图1    b :原图2    m :mask掩摸图Mat blend(Mat &a, Mat &b, Mat &m) {int width = a.cols;int height = a.rows;Mat dst = Mat::zeros(a.size(), a. type());Vec3b rgb1;Vec3b rgb2;int r1 = 0, g1 = 0, b1 = 0;int r2 = 0, g2 = 0, b2 = 0;int red = 0, green = 0, blue = 0;int w = 0;float w1 = 0, w2 = 0;for( int row = 0; row < height; row++) {for( int col = 0; col < width; col++) {rgb1 = a.at<Vec3b>(row, col);rgb2 = b.at<Vec3b>(row, col);w = m.at<uchar>(row, col);w2 = w / 255.0f;w1 = 1.0f- w2;b1 = rgb1[ 0] & 0xff;g1 = rgb1[ 1] & 0xff;r1 = rgb1[ 2] & 0xff;b2 = rgb2[ 0] & 0xff;g2 = rgb2[ 1] & 0xff;r2 = rgb2[ 2] & 0xff;red = ( int)(r1*w1 + r2*w2);green = ( int)(g1*w1 + g2*w2);blue = ( int)(b1*w1 + b2*w2);// outputdst.at<Vec3b>(row, col)[ 0] = blue;dst.at<Vec3b>(row, col)[ 1] = green;dst.at<Vec3b>(row, col)[ 2] = red;}}return dst;
}
根据拉普拉斯金字塔重建高分辨率近似原图的代码如下:// 重建拉普拉斯金字塔vector<Mat> ls;for( int i = 0; i<level; i++)
{Mat a = la[i];Mat b = lb[i];Mat m = maskPyramid[i];ls.push_back(blend(a, b, m));
}// 重建原图
Mat temp;
for( int i = level - 1; i >= 0; i--)
{pyrUp(currentImage, temp, ls[i].size());add(temp, ls[i], currentImage);
}

二、拉普拉斯金字塔图像融合

一些图像融合算法

图像拼接主要可以分为两个步骤:图像配准和图像融合。其中图像配准的目的是将图一场景中不同视角的图像投影到同一平面并进行对准。

经过图像配准之后,就需要进行图像融合。而图像融合的目的就是使两幅图像的重叠区域过渡自然且平滑。在上图中,可以看到明显的边界,这对拼接来说是无法接受的。这主要是因为外部亮度的变化(天空飘过了一朵萌萌的云彩?)以及曝光时相机参数不一致导致的。要消除或缓和这种现象,就需要进行图像融合。

主流的图像融合算法:
1)加权平均法。这个很好理解,即简单的使用加权的方式从左边过渡到右边。这种方法效果一般,但算法实现极其简单,速度快。
2)羽化算法 。这种方法过渡会比加权平均法自然,但会造成不好的模糊效果。
3)拉普拉斯金字塔融合。有的地方也称为多分辨率融合算法。这种方法是将图像建立一个拉普拉斯金字塔,其中金字塔的每一层都包含了图像不同的频段。分开不同频段进行融合效果出奇的好。

算法原理

1)首先建立两幅图像高斯金字塔,然后建立一定层数的拉普拉斯金字塔。拉普拉斯金字塔的层数越高,融合效果越好。层数N作为一个参数。
2)传入一个mask掩膜,代表了融合的位置。比如说想在两图的中间进行融合,那么掩膜图像的左半为255,右半为0,反过来是一样的。根据这个mask建立一个高斯金字塔,用于后续融合,层数为N+1。
3)根据mask将两幅图像的拉普拉斯金字塔的图像进行相加,mask为权值。相加的结果即为一个新的金字塔。同时,两幅图像的高斯金字塔的N+1层也进行这个操作,记这个图像为IMG1。
4)根据这个新的金字塔重建出最终的图像,重建的过程跟一般的拉普拉斯金字塔一样。首先对IMG1上采样,然后跟新金字塔的顶层相加,得到IMG2。IMG2进行上采样后跟下一层相加,得到IMG3。重复这个过程,最终得到的结果就是拉普拉斯金字塔融合算法的结果。

注:因为mask建立金字塔的过程中使用了高斯模糊,所以融合的边缘是比较平滑的。

算法实现

#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>using namespace std;
using namespace cv;#define IMG1_PATH "apple.png"
#define IMG2_PATH "orange.png"/*** @brief The LaplacianBlending class* @private leftImg & rightImg 用于拼接的左图和右图* @private blendMask 用于融合的掩膜,值为加权平均的系数*/
class LaplacianBlending {
private:Mat leftImg;            //左图Mat rightImg;           //右图Mat blendMask;          //融合所需要的mask//Laplacian Pyramids  左图、右图、结果图拉普拉斯金字塔vector<Mat> leftLapPyr, rightLapPyr, resultLapPyr;//左图、右图、结果图 最高层图像(也就是最小分辨率图像)Mat leftHighestLevel, rightHighestLevel, resultHighestLevel;//掩摸mask高斯金字塔 mask为三通道图像,方便矩阵相乘vector<Mat> maskGaussianPyramid;//层数int levels;//创建金字塔void buildPyramids(){buildLaplacianPyramid(leftImg, leftLapPyr, leftHighestLevel);buildLaplacianPyramid(rightImg, rightLapPyr, rightHighestLevel);buildGaussianPyramid();}//创建高斯金字塔  /金字塔内容为每一层的掩模maskvoid buildGaussianPyramid(){        assert(leftLapPyr.size() > 0);maskGaussianPyramid.clear();Mat currentImg;cvtColor(blendMask, currentImg, CV_GRAY2BGR);//保存mask金字塔的每一层图像maskGaussianPyramid.push_back(currentImg); //0 - levelcurrentImg = blendMask;for (int l = 1; l < levels + 1; l++) {Mat _down;if (leftLapPyr.size() > l)pyrDown(currentImg, _down, leftLapPyr[l].size());elsepyrDown(currentImg, _down, leftHighestLevel.size()); //lowest levelMat down;cvtColor(_down, down, CV_GRAY2BGR);//add color blend mask into mask PyramidmaskGaussianPyramid.push_back(down);string winName = to_string((long long)l);imshow(winName,down);
//          waitKey(0);currentImg = _down;}}//创建拉普拉斯金字塔void buildLaplacianPyramid(const Mat& img, vector<Mat>& lapPyr, Mat& HighestLevel){lapPyr.clear();Mat currentImg = img;for (int l = 0; l < levels; l++) {Mat down, up;pyrDown(currentImg, down);pyrUp(down, up, currentImg.size());Mat lap = currentImg - up;lapPyr.push_back(lap);currentImg = down;}currentImg.copyTo(HighestLevel);}//重建图片 从 拉普拉斯金字塔中Mat reconstructImgFromLapPyramid(){//将左右laplacian图像拼成的resultLapPyr金字塔中每一层//从上到下插值放大并与残差相加,即得blend图像结果Mat currentImg = resultHighestLevel;for (int l = levels - 1; l >= 0; l--){Mat up;pyrUp(currentImg, up, resultLapPyr[l].size());currentImg = up + resultLapPyr[l];}return currentImg;}//混合拉普拉斯金字塔//获得每层金字塔中直接用左右两图Laplacian,变换拼成的图像resultLapPyr(结果拉普拉斯金字塔)void blendLapPyrs(){//结果拉普拉斯金字塔 最高层 混合resultHighestLevel = leftHighestLevel.mul(maskGaussianPyramid.back()) +rightHighestLevel.mul(Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid.back());//结果拉普拉斯金字塔 除最高层以外的其他层混合for (int l = 0; l < levels; l++){Mat A = leftLapPyr[l].mul(maskGaussianPyramid[l]);Mat antiMask = Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid[l];Mat B = rightLapPyr[l].mul(antiMask);Mat blendedLevel = A + B;resultLapPyr.push_back(blendedLevel);}}public:LaplacianBlending(const Mat& _left, const Mat& _right, const Mat& _blendMask, int _levels) :  //construct function, used in LaplacianBlending lb(l,r,m,4);leftImg(_left), rightImg(_right), blendMask(_blendMask), levels(_levels){assert(_left.size() == _right.size());assert(_left.size() == _blendMask.size());//创建拉普拉斯金字塔和高斯金字塔buildPyramids();//每层金字塔图像合并为一个blendLapPyrs();};Mat blend(){//重建拉普拉斯金字塔return reconstructImgFromLapPyramid();}
};//拉普拉斯融合
Mat LaplacianBlend(const Mat &left, const Mat &right, const Mat &mask)
{LaplacianBlending laplaceBlend(left, right, mask, 10);return laplaceBlend.blend();
}int main() {Mat leftImg = imread(IMG1_PATH);Mat rightImg = imread(IMG2_PATH);int hight = leftImg.rows;int width = leftImg.cols;Mat leftImg32f, rightImg32f;leftImg.convertTo(leftImg32f, CV_32F);rightImg.convertTo(rightImg32f, CV_32F);//创建用于混合的掩膜,这里在中间进行混合Mat mask = Mat::zeros(hight, width, CV_32FC1);mask(Range::all(), Range(0, mask.cols * 0.5)) = 1.0;Mat blendImg = LaplacianBlend(leftImg32f, rightImg32f, mask);blendImg.convertTo(blendImg, CV_8UC3);imshow("left", leftImg);imshow("right", rightImg);imshow("blended", blendImg);waitKey(0);return 0;
}

结果:

左图(苹果)

右图(橙子)

拉普拉斯金字塔融合结果

最后

此篇文章是参考了其他博客,然后稍作修改、整合。感谢原博主。

参考博客:

http://www.sohu.com/a/260164456_823210

https://www.jianshu.com/p/3185cca3f082

opencv 图像金字塔及图像重建、融合相关推荐

  1. opencv图像金字塔的介绍

    1.学习目标: 掌握opencv图像金字塔的原理 学习内容: 1.什么是图像金字塔? 2.图像金字塔有什么用? 3.图像金字塔实现方式 学习产出: 1. 什么是图像金字塔? 图像金字塔(如图 1 所示 ...

  2. Python,OpenCV图像金字塔cv2.pyrUp(), cv2.pyrDown()

    Python,OpenCV图像金字塔cv2.pyrUp, cv2.pyrDown 1. 效果图 2. 原理 2.1 什么是图像金字塔 2.2 金字塔分类 2.3 应用 3. 源码 参考 这篇博客将介绍 ...

  3. OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔总结

    我们经常会将某种尺寸的图像转换为其他尺寸的图像,如果放大或者缩小图片的尺寸,笼统来说的话,可以使用OpenCV为我们提供的如下两种方式: <1> resize函数.这是最直接的方式, &l ...

  4. 【OpenCV新手教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放...

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨) ...

  5. 【OpenCV入门教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨) ...

  6. OpenCV图像金字塔pyrDown和pyrUp的实例(附完整代码)

    OpenCV图像金字塔pyrDown和pyrUp的实例 OpenCV图像金字塔pyrDown和pyrUp的实例 OpenCV图像金字塔pyrDown和pyrUp的实例 #include "i ...

  7. OpenCV图像金字塔

    图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构.一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合.其通过梯次向下采样获得,直 ...

  8. FCN全卷积网络—upsampling(上采样)——OpenCV图像金字塔

    一.上采样理论 1.1 bilinear 1.2 Deconvolution(反卷积) 1.3 unpooling 二.OpenCV金字塔:高斯金字塔.拉普拉斯金字塔与图片缩放 一.上采样理论 FCN ...

  9. OpenCV 图像金字塔buildPyramid、pyrDown、pyrUp

    返回OpenCV算子速查表 升采样 pyrDown,降采样 pyrUp,图像金字塔buildPyramid 1. 函数定义 1.1 降采样 pyrDown 1.2 升采样 pyrUp 1.3 buil ...

最新文章

  1. 七天学会NodeJS
  2. 软件随想: 软件 = 程序 + 软件工程
  3. PHP同时连接多个mysql数据库_php如何同时连接多个数据库
  4. UVA 270 Lining Up
  5. vulhub安装教程
  6. PHP 常用设计模式 (转载)
  7. hive 前7天标准差_为啥科目三考试前只让练7天?教练实话实说:这是为你们好...
  8. Python函数名挂载变量
  9. 宝藏又小众的海边场景 海底 海岛unity3d模型素材网站分享
  10. echarts中国及世界经纬度坐标
  11. 图片文件Exif信息详细说明
  12. 蒟蒻的笔记本二、tarjan
  13. php泥浆护壁,扩孔泥浆护壁式集束式潜孔锤技术
  14. 解决虚拟机突然断网问题
  15. canvas全局合成画月牙_画房子一日营 | 园林设计写生系列课程
  16. arccatalog点要素显示不完_shp文件转为dwg之后在arcgis下打开属性表有高程信息但在cad里面打开为何没高程 - 地学 - 小木虫 - 学术 科研 互动社区...
  17. python安装lap_AP 升级到 LAP,或 LAP 降到 AP 的方法
  18. 微软公司按照成熟度把服务器端企业,战略性新兴产业基础知识(公需课作业).pdf...
  19. linux下 etho网卡设置
  20. 苹果改变手机型号_苹果的低碳铝将改变气候

热门文章

  1. 智能护眼台灯芯片方案开发usb充电小夜灯IC感应灯触摸单片机
  2. Git项目库删除找回
  3. 《易经》对中华文化的影响
  4. [JSTL]标签的使用
  5. Linux Ubuntu系统设置成中文语言
  6. macOS中安装zsh,并配置些重要插件
  7. librosa@soundFile音频读取和绘图@声道@通道@包络
  8. mac node如何升级版本
  9. signature=664f9760ad1f1ac8fb5bff722b4da240,恶意软件分析 URL链接扫描 免费在线病毒分析平台 | 魔盾安全分析...
  10. SA387Gr11Cl2是什么材质