图像拼接(一):柱面投影+模板匹配+渐入渐出融合

article/2025/9/27 3:47:15

这种拼接方法的假设前提是:待拼接的两幅图像之间的变换模型是平移模型,即两幅图像同名点位置之间只相差两个未知量: Δx Δy ,自由度为2,模型收得最紧。所以只有所有图像都是用同一水平线或者同一已知倾斜角的摄像机拍摄时,这种方法才适用。
整个过程为:首先对输入的两幅图像做柱面投影;然后通过模板匹配求取 Δx Δy ;最后采用渐入渐出的融合方式拼接两幅图像。

柱面投影

为了保证拼接后的视觉一致性,所以需要将待拼接的图像分别投影到一个标准的坐标系下,然后再进行图像拼接。由于柱面坐标的变换比较简单并且投影图像与其投影到圆柱表面的位置无关,用其描述的柱面全景图像可在水平方向上满足360度环视,具有较好的视觉效果,所以可采用柱面投影完成图像拼接。
下面为柱面投影采用的公式, x y 为柱面投影后的图像坐标, x y为图像原来的坐标, width height 为图像宽高, f 为相机焦距,我的理解是:因为width height 都是在图像坐标系下,所以这个 f 是相对于图像的,我是根据图像大小以及视场角最做的估计。

x=fatan(x0.5widthf)+fatan(0.5widthf)

y=f(y0.5height)(x0.5width)2+f2+0.5height

下面是柱面校正的代码,事无巨细都是自己写的,因为没有找到上述公式的反演公式,直接正向插值了,好在出来的效果还不错。

/**柱面投影函数*参数列表中imgIn为输入图像,f为焦距*返回值为柱面投影后的图像
*/
Mat cylinder(Mat imgIn, int f)
{int colNum, rowNum;colNum = 2 * f*atan(0.5*imgIn.cols / f);//柱面图像宽rowNum = 0.5*imgIn.rows*f / sqrt(pow(f, 2)) + 0.5*imgIn.rows;//柱面图像高Mat imgOut = Mat::zeros(rowNum, colNum, CV_8UC1);Mat_<uchar> im1(imgIn);Mat_<uchar> im2(imgOut);//正向插值int x1(0), y1(0);for (int i = 0; i < imgIn.rows; i++)for (int j = 0; j < imgIn.cols; j++){x1 = f*atan((j - 0.5*imgIn.cols) / f) + f*atan(0.5*imgIn.cols / f);y1 = f*(i - 0.5*imgIn.rows) / sqrt(pow(j - 0.5*imgIn.cols, 2) + pow(f, 2)) + 0.5*imgIn.rows;if (x1 >= 0 && x1 < colNum&&y1 >= 0 && y1<rowNum){im2(y1, x1) = im1(i, j);}}return imgOut;
}

模板匹配

通过模板匹配的方法求取平移变换参数

/**求平移量*参数表为输入两幅图像(有一定重叠区域)*返回值为点类型,存储x,y方向的偏移量
*/
Point2i getOffset(Mat img, Mat img1)
{Mat templ(img1, Rect(0, 0.4*img1.rows, 0.2*img1.cols, 0.2*img1.rows));Mat result(img.cols - templ.cols + 1, img.rows - templ.rows + 1, CV_8UC1);//result存放匹配位置信息matchTemplate(img, templ, result, CV_TM_CCORR_NORMED);normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());double minVal; double maxVal; Point minLoc; Point maxLoc; Point matchLoc;minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());matchLoc = maxLoc;//获得最佳匹配位置int dx = matchLoc.x;int dy = matchLoc.y - 0.4*img1.rows;//右图像相对左图像的位移Point2i a(dx, dy);return a;
}

线性融合

采用渐入渐出融合,其实就是在重叠区域,对两幅图像的像素,线性地分配权值。公式: img=dimg1+(1d)img2 ;其中img为融合后的图像,img1和img2为待拼接的两幅图像。d为重叠区域中某个像素点到边界的距离。

/*渐入渐出拼接*参数列表中,img1,img2为待拼接的两幅图像,a为偏移量*返回值为拼接后的图像
*/
Mat linearStitch(Mat img, Mat img1, Point2i a)
{int d = img.cols - a.x;//过渡区宽度int ms = img.rows - abs(a.y);//拼接图行数int ns = img.cols + a.x;//拼接图列数Mat stitch = Mat::zeros(ms, ns, CV_8UC1);//拼接Mat_<uchar> ims(stitch);Mat_<uchar> im(img);Mat_<uchar> im1(img1);if (a.y >= 0){Mat roi1(stitch, Rect(0, 0, a.x, ms));img(Range(a.y, img.rows), Range(0, a.x)).copyTo(roi1);Mat roi2(stitch, Rect(img.cols, 0, a.x, ms));img1(Range(0, ms), Range(d, img1.cols)).copyTo(roi2);for (int i = 0; i < ms; i++)for (int j = a.x; j < img.cols; j++)ims(i, j) = uchar((img.cols - j) / float(d)*im(i + a.y, j) + (j - a.x) / float(d)*im1(i, j - a.x));}else{Mat roi1(stitch, Rect(0, 0, a.x, ms));img(Range(0, ms), Range(0, a.x)).copyTo(roi1);Mat roi2(stitch, Rect(img.cols, 0, a.x, ms));img1(Range(-a.y, img.rows), Range(d, img1.cols)).copyTo(roi2);for (int i = 0; i < ms; i++)for (int j = a.x; j < img.cols; j++)ims(i, j) = uchar((img.cols - j) / float(d)*im(i, j) + (j - a.x) / float(d)*im1(i + abs(a.y), j - a.x));}return stitch;
}

实验效果

写一个包含主函数的文件调用上述方法:

#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"
#include<iostream>
#include<time.h>int main()
{Mat img = imread("frame1.jpg", 0);//左图像Mat img1 = imread("frame2.jpg", 0);//右图像imshow("源图像-左", img);imshow("源图像-右", img1);double t = (double)getTickCount();//柱形投影double t3 = (double)getTickCount();img = cylinder(img,1000);img1 = cylinder(img1, 1000);t3 = ((double)getTickCount() - t3) / getTickFrequency();//匹配double t1 = (double)getTickCount();Point2i a = getOffset(img, img1);t1 = ((double)getTickCount() - t1) / getTickFrequency();//拼接double t2 = (double)getTickCount();Mat stitch = linearStitch(img, img1, a);t2 = ((double)getTickCount() - t2) / getTickFrequency();t = ((double)getTickCount() - t) / getTickFrequency();cout << "各阶段耗时:"<< endl;cout << "柱面投影:" << t3 << '\n' << "模板匹配:" << t1 << '\n' << "渐入渐出拼接:" << t2 << endl;cout << "总时间:" << t << endl;imshow("柱面校正-左图像", img);imshow("柱面校正-右图像", img1);imshow("拼接结果", stitch);imwrite("rectify.jpg", img);imwrite("rectify1.jpg", img1);imwrite("stitch.jpg", stitch);waitKey(0);return 0;
}

首先读取两幅源图像:
这里写图片描述

这里写图片描述

柱面投影之后:
这里写图片描述

这里写图片描述
最后的拼接结果:
这里写图片描述
拼接时间效率:
测试环境为Intel(R) Core(TM) i3-2350M CPU @ 2.3GHz;Win 10+VS2013;源图像像素分辨率为640*480。
这里写图片描述

可以看出整体效果还行,但细节很差,比如重叠区域的墙上电线出现了重影。时间效率方面,自己写的柱面投影函数耗时明显,有待优化。


http://chatgpt.dhexx.cn/article/OqdySFQy.shtml

相关文章

2D射影儿何和变换——柱面投影,图像拼接柱面投影

引入二维空间(以下简称2D) 的射影变换 这些变换发生在用透视摄像机对平面摄像的时候. 该章偏重于入门介绍并为三维空间(以下简称3D) 几何铺路. 大多数的概念在2D 中比3D 中更容易理解和可视化. 本章介绍射影变换&#xff0c;包括它的特殊悄况:仿射和相似变换; 并把注意力…

鱼眼图像与柱面的投影

鱼眼图像到柱面的反投影及柱面到鱼眼图像的投影 https://blog.csdn.net/c20081052/article/details/80999904 鱼眼图像到柱面图像的投影公式推导参考链接&#xff0c;自己照着推导过&#xff0c;应该是没有问题的。这个是平面图像到柱面的投影&#xff0c;我理解的鱼眼图像也是…

【论文笔记】激光点云柱面投影图的显著性检测 LiDAR Imaging-based Attentive Perception

内华达大学里诺分校 在嵌入式处理器设备上(飞行器)达到了毫秒级执行时间, 使用的激光雷达型号 :  OUSTER OS1-64 &#xff08;图像尺寸204810&#xff09;&#xff0c;OUSTER OS0-128&#xff08;图像尺寸204810&#xff09; 这种激光雷达可以提供的信息包括: 距离, 强度, 反射…

图像拼接---图片柱面投影简单实现

算法思想参考&#xff1a;http://blog.csdn.net/weixinhum/article/details/50611750 柱面投影是图片拼接的前期的一部分工作&#xff0c;以下代码只是简单的实现了投影&#xff0c;还可以优化&#xff0c; 柱面半径设置位图片宽度的一半&#xff0c;即 R width/2 代码运算…

2.8 投影柱面

空间曲线 在xOy坐标面上的投影曲线是 投影柱面的参数方程为 例 2.8.1 将以下空间曲线投影到xOy坐标面&#xff0c;试作出投影柱面的图形。 解 输入以下代码&#xff1a; with(plots): x:t->cos(t): y:t->sin(t): z:t->t: S:2: T:6:K:50: quxian:spacecurve([x(t),y(t…

【Opencv】2D射影儿何和变换——柱面投影,图像拼接柱面投影

引入二维空间(以下简称2D) 的射影变换 这些变换发生在用透视摄像机对平面摄像的时候. 该章偏重于入门介绍并为三维空间(以下简称3D) 几何铺路. 大多数的概念在2D 中比3D 中更容易理解和可视化. 本章介绍射影变换&#xff0c;包括它的特殊悄况:仿射和相似变换; 并把注意力主要…

matlab 柱面投影,图像拼接(不投影到柱面)(渐入渐出融合) matlab程序

1,先拍摄一组图片,比如两幅图:A、B 我直接用网上的两幅图: 2,分别投影到柱面坐标系 就用自己写的柱面投影程序 matlab里 结果: 3,开始配准第一步:SIFT得到匹配对(直接用OpenCV里自带的) 有两三对误匹配对,后来调整阈值得到没有误匹配对的结果。 4,配准第二步:根据匹…

opencv柱面投影,C语言实现

在做全景拼接的时候&#xff0c;为了保持图片中的空间约束与视觉的一致性&#xff0c;需要进行柱面投影&#xff0c;否则离中心图像距离越远的图像拼接后变形越大。 柱面投影公式为 这个是https://blog.csdn.net/zouxin_88/article/details/85167602的代码&#xff0c;rgb彩色…

柱面投影matlab程序

拼接之前要进行柱面、立方体面或者球面投影&#xff0c;《全景拼接的关键技术研究》选的是柱面投影&#xff0c;根据其理论有&#xff1a; %假设相机市场角为45度 %反投影到柱面时左右有缝隙了 Aimread(F:\fisheye\kk.jpg); [H,W,k]size(A); fW/(2*tan(pi/4/2)); %视场角越…

柱面投影、拼接视差、球面投影

1. 图像拼接传统做法: 特征点提取:sift、surf、orb等特征点提取; 基于特征点的配准:RANSAC方法剔除匹配点并拟合图像变换矩阵(全局单应性矩阵); 图像融合:先确定缝合线,再利用加权融合、多频带融合的方法融合; 方法:除了按照上文提到的顺序利用opencv进行拼接,还可以…

opencv柱面投影

在做全景拼接的时候&#xff0c;为了保持图片中的空间约束与视觉的一致性&#xff0c;需要进行柱面投影&#xff0c;否则离中心图像距离越远的图像拼接后变形越大。 柱面投影公式为 变换效果如下&#xff1a; int main() {cv::Mat image1 cv::imread("images/1.jpg"…

图片柱面投影简单实现

转自&#xff1a;https://blog.csdn.net/u010551600/article/details/78461142 柱面投影是图片拼接的前期的一部分工作&#xff0c;以下代码只是简单的实现了投影&#xff0c;还可以优化&#xff0c; 柱面半径设置位图片宽度的一半&#xff0c;即 R width/2 代码运算流程是…

柱面投影

做全景拼接时需要将图像统一到一个视角里&#xff0c;常用的柱面投影&#xff0c;其基本原理及公式如下&#xff08;原文&#xff09;。 【Octave】柱面投影简析 我是分割线 在做全景拼接的时候&#xff0c;为了保持图片中的空间约束与视觉的一致性&#xff0c;需要做一定的预…

图像柱面投影

由于图像序列是实体景物在不同坐标系下的二维投影&#xff0c;直接对拍摄图像进行拼接无法满足视觉一致性&#xff0c;所以需要将待拼接的图像分别投影到一个标准的坐标系下&#xff0c;然后再进行图像的拼接。全景图生成系统可以采用圆柱体、立方体和球体等模型来实现。由于柱…

柱面投影介绍与python实现(一)

简介 本文主要介绍柱面投影变换,将这种变换用于图像处理,可以产生图像扭曲的效果,如下图所示,产生了将平面图像投影到了柱面上的视觉效果。博客最后给出了柱面投影的python实现,供读者参考。 数学原理 如下图所示,矩形GHEF为待处理的原图,投影到柱面上之后则变成了…

【Octave】柱面投影简析

我是分割线 在做全景拼接的时候&#xff0c;为了保持图片中的空间约束与视觉的一致性&#xff0c;需要做一定的预处理&#xff0c;可以是球面投影&#xff0c;柱面投影等。 如果仅仅是做水平方向的拼接&#xff0c;则做柱状投影就好了 一. 原理 把平面图像投影到圆柱的曲面上。…

拖库 洗库 撞库

间接转载地址: http://blog.csdn.net/daliaojie/article/details/42171177 一,背景: 用户数据泄露一直是如今互联网世界的一个焦点,从最近的京东撞库抹黑事件,到之前的CSDN,如家用户数据的泄露,服务商和黑客之间在用户数据这个舞台上一直在进行着旷日持久的攻防战。 对于…

分享一个验证码暴力撞库漏洞的案例

记录一个验证码暴力破解的案例&#xff0c;安全问题不容忽视呀。 某公司接到用户反馈&#xff0c;应用存在安全漏洞&#xff0c;通过技术手段可以在无手机情况下&#xff0c;获取验证码&#xff0c;直接修改密码成功。如果用户密码被他人修改成功&#xff0c;直接涉及到资产损…

深入浅出了解撞库攻击!

1. 撞库的原理和危害 “撞库”&#xff08;Credential Stuffing Attack&#xff09;在网络安全中是一个古老的概念&#xff0c;按中文的字面意思解读&#xff0c;就是“碰撞数据库”的意思。“碰撞”意味着碰运气&#xff0c;即不一定能成功&#xff1b;而“数据库”中往往存储…

使用 Burp Suite 暴力破解密码 撞库攻击 从0到1手摸手教学

说明 一个学习的过程 增加自己网络安全知识 切勿用于违法用途 设置密码尽量使用6位以上并规避简单数字组合、加强对同一ip的频繁访问次数限制、设置人机验证减小撞库攻击的危害 用到的工具&环境 本地环境 kali 2022 Burp Suite FireFox 靶机环境 一台服务器 CentO…