基于SIFT的图像Matlab拼接教程

news2024/11/24 3:13:54

前言

图像拼接技术,将普通图像或视频图像进行无缝拼接,得到超宽视角甚至360度的全景图,这样就可以用普通数码相机实现场面宏大的景物拍摄。利用计算机进行匹配,将多幅具有重叠关系的图像拼合成为一幅具有更大视野范围的图像,这就是图像拼接的目的。

一、技术路线

图1 基于SIFT图像拼接技术路线图

二、实现过程

2.1 SIFT特征点提取

Sift算法的三大工序为:(1)提取关键点;(2)对关键点附加详细的信息(局部特征)也就是所谓的描述器;(3)通过两方特征点(附带上特征向量的关键点)的两两比较找出相互匹配的若干对特征点,也就建立了景物间的对应关系。即可以归结为在不同尺度空间上查找特征点(关键点)的问题。

图2 SIFT算法流程

提取关键点和对关键点附加详细的信息(局部特征)也就是所谓的描述器可以称做是Sift特征的生成,即从多幅图像中提取对尺度缩放、旋转、亮度变化无关的特征向量,Sift特征的生成一般包括以下几个步骤:

  • 构建尺度空间,检测极值点,获得尺度不变性;

  • 特征点过滤并进行精确定位;

  • 为特征点分配方向值;

  • 生成特征描述子。

以特征点为中心取16*16的邻域作为采样窗口,将采样点与特征点的相对方向通过高斯加权后归入包含8个bin的方向直方图,最后获得4*4*8的128维特征描述子。

当两幅图像的Sift特征向量生成以后,下一步就可以采用关键点特征向量的欧式距离来作为两幅图像中关键点的相似性判定度量。取图1的某个关键点,通过遍历找到图像2中的距离最近的两个关键点。在这两个关键点中,如果次近距离除以最近距离小于某个阙值,则判定为一对匹配点。

SIFT算法实现分为两个部分,第一个函数sift(img)函数输入1张图像,返回图像特征点;第二个函数siftMatch(img1,img2)输入两张图像,进行两张图像的匹配。

(1)函数1:返回图像的SIFT特征点

function [descriptors, locs] = sift(img)
% 本函数返回图像的SIFT特征点
function [descriptors, locs] = sift(img)
%输入彩色影像,转换为灰度图.
img = rgb2gray(img);
[rows, cols] = size(img);  
f = fopen('tmp.pgm', 'w');
if f == -1
error('Could not create file tmp.pgm.');
end
fprintf(f, 'P5\n%d\n%d\n255\n', cols, rows);
fwrite(f, img', 'uint8');
fclose(f); 
ifisunix
command = '!./sift ';
else
command = '!siftWin32 ';
end
command = [command ' <tmp.pgm>tmp.key'];
eval(command); 
g = fopen('tmp.key', 'r');
if g == -1
error('Could not open file tmp.key.');
end
[header, count] = fscanf(g, '%d %d', [1 2]);
if count ~= 2
error('Invalid keypoint file beginning.');
end
num = header(1);
len = header(2);
iflen ~= 128
error('Keypoint descriptor length invalid (should be 128).');
end
% 输出矩阵
locs = double(zeros(num, 4));
descriptors = double(zeros(num, 128));
fori = 1:num
    [vector, count] = fscanf(g, '%f %f %f %f', [1 4]); %row col scale ori
if count ~= 4
error('Invalid keypoint file format');
end
locs(i, :) = vector(1, :);

    [descrip, count] = fscanf(g, '%d', [1 len]);
if (count ~= 128)
error('Invalid keypoint file value.');
end
descrip = descrip / sqrt(sum(descrip.^2));
descriptors(i, :) = descrip(1, :);
end
fclose(g); 
delete('tmp.pgm');

(2)函数2:读入两幅图像,寻找它们的SIFT特征,显示相互匹配的特征点的连线

function [matchLoc1 matchLoc2] = siftMatch(img1, img2)
% 本函数读入两幅图像,寻找它们的SIFT特征,显示相互匹配的特征点的连线
% 返回两幅图像相匹配的特征点
function [matchLoc1 matchLoc2] = siftMatch(img1, img2)
% 寻找两幅图的特征点
[des1, loc1] = sift(img1);
[des2, loc2] = sift(img2);
distRatio = 0.6;   
%为第一幅的特征点寻找匹配的第二幅图中的特征点
des2t = des2';                         
matchTable = zeros(1,size(des1,1));
fori = 1 : size(des1,1)
dotprods = des1(i,:) * des2t;       
   [vals,indx] = sort(acos(dotprods));  
if (vals(1) <distRatio * vals(2))
matchTable(i) = indx(1);
else
matchTable(i) = 0;
end
end
%保存匹配数据和匹配表
%将两幅图像并排显示
img3 = appendimages(img1,img2);
% 在两幅图中画出可以接受的相互匹配的特征点连线
figure('Position', [100 100 size(img3,2) size(img3,1)]);
colormap('gray');
imagesc(img3);
holdon;
cols1 = size(img1,2);
fori = 1: size(des1,1)
if (matchTable(i) > 0)
    line([loc1(i,2) loc2(matchTable(i),2)+cols1], ...
         [loc1(i,1) loc2(matchTable(i),1)], 'Color', 'c');
end
end
holdoff;
num = sum(matchTable> 0);
fprintf('Found %d matches.\n', num);
idx1 = find(matchTable);
idx2 = matchTable(idx1);
x1 = loc1(idx1,2);
x2 = loc2(idx2,2);
y1 = loc1(idx1,1);
y2 = loc2(idx2,1);
matchLoc1 = [x1,y1];
matchLoc2 = [x2,y2];
end

2.2 RANSAC算法进行图像配准

在进行两幅或多幅图像间的镶嵌及配准时,通常情况下都会有一个参考图像或者基准图像作为处理的标准。其中就需要建立原始图像到参考图像的变换模型,而模型参数的稳健估计就成了关键技术之一。在实际问题中,得到的数据往往并不是完全准确的,常常伴随着许多异常数据,于是问题的关键在于如何处理不符合实际模型的异常数据。

一个简单的例子是从一组观测数据中找出合适的2维直线。假设观测数据中包含局内点和局外点,其中局内点近似的被直线所通过,而局外点远离于直线。简单的最小二乘法不能找到适应于局内点的直线,原因是最小二乘法尽量去适应包括局外点在内的所有点。相反,RANSAC能得出一个仅仅用局内点计算出模型,并且概率还足够高。但是,RANSAC并不能保证结果一定正确,为了保证算法有足够高的合理概率,我们必须小心的选择算法的参数。

图3 左图:包含很多局外点的数据集;右图:RANSAC找到的直线(局外点并不影响结果)

RANSAC只能从特定的数据集中估计出一个模型,如果存在两个(或多个)模型,RANSAC不能找到别的模型。

% RANSAC 实现函数
[H corrPtIdx] = ransac1(pts1,pts2,coef,@solveHomo,@calcDist);
……
% ransac1函数返回单应矩阵H和满足距离阈值的点的下标
function [f inlierIdx] = ransac1( x,y,ransacCoef,funcFindF,funcDist )
minPtNum = ransacCoef.minPtNum; %用于拟合模型所需最少的样本点个数
iterNum = ransacCoef.iterNum;   %迭代·次数
thInlrRatio = ransacCoef.thInlrRatio; %局内点数量阈值
thDist = ransacCoef.thDist;   % 局内点到模型线之间距离阈值
ptNum = size(x,2);     %特征点矩阵的列数
thInlr = round(thInlrRatio*ptNum);%局内点数量阈值,小于该值的模型舍弃
inlrNum = zeros(1,iterNum);%存放每次构建模型后,满足距离阈值的点个数
fLib = cell(1,iterNum);%存放所有构建的单应模型
%迭代计算
for p = 1:iterNum
    % 1.fit using random points
    sampleIdx = randIndex(ptNum,minPtNum);%从162个特征点中选择四个,用于构建单应矩阵
    f1 = funcFindF(x(:,sampleIdx),y(:,sampleIdx));%构建单应矩阵,即某种模型
    
    % 2.count the inliers, if more than thInlr, refit; else iterate
    dist = funcDist(f1,x,y);%计算所有特征点到模型的距离
    inlier1 = find(dist<thDist);%满足距离阈值的点的下标
    inlrNum(p) = length(inlier1);%满足条件的点个数
    if length(inlier1) <thInlr, continue; end  %点个数小于点个数阈值,舍弃该模型
    fLib{p} = funcFindF(x(:,inlier1),y(:,inlier1));%重构模型
end

% 3.choose the coef with the most inliers
[xxx,idx] = max(inlrNum);%xxx为最多的点个数;idx为xxx值出现的下标(xxx值相同的模型也是相同的)
f = fLib{idx};%确定最后的模型
dist = funcDist(f,x,y);%特征点到模型距离
inlierIdx = find(dist<thDist);%满足距离阈值的点的下标

end

2.3 图像配准——单应矩阵求解

为了实现影像匹配,在提取特征点后,变换矩阵H的求解是图像配准的核心。主要用到RANSAC函数迭代精炼H变换矩阵。

函数solveHomo和函数calcDist在RANSAC函数中被反复调用,最终得到最优点及对应的单应矩阵H。

在实际计算中仍把单应性矩阵作为9个元素来处理,这是由于齐次坐标变换之后仍需归一化得到实际坐标,因此对应点组数n至少需要5个,才能保证方程组有解。

function H = solveHomo(pts1,pts2)

%输入左右像对应的特征点,输出变换矩阵H
% RANSAC函数每次迭代中被调用

n = size(pts1,2);
A = zeros(2*n,9);
A(1:2:2*n,1:2) = pts1';
A(1:2:2*n,3) = 1;
A(2:2:2*n,4:5) = pts1';
A(2:2:2*n,6) = 1;
x1 = pts1(1,:)';
y1 = pts1(2,:)';
x2 = pts2(1,:)';
y2 = pts2(2,:)';
A(1:2:2*n,7) = -x2.*x1;
A(2:2:2*n,7) = -y2.*x1;
A(1:2:2*n,8) = -x2.*y1;
A(2:2:2*n,8) = -y2.*y1;
A(1:2:2*n,9) = -x2;
A(2:2:2*n,9) = -y2;           %构造系数矩阵

[evec,tt] = eig(A'*A);       %求特征值和特征向量
H = reshape(evec(:,1),[3,3])';
H = H/H(end); % make H(3,3) = 1

end

2.4 图像合成

由于普通的相机在拍摄照片时会自动选取曝光参数,这会使输入图像之间存在亮度差异,导致拼接后图像缝合线两端出现明显的明暗变化。因此,在融合过程中需要对缝合线进行处理,以平滑两幅图像两端的明暗差异。进行图像拼接缝合线的方法有很多种,如颜色插值和多分辨率样条技术等,本次研究使用了快速简单的加权平滑算法处理拼接缝问题。

图像重叠区域中像素点的灰度值Pixel由两幅图像对应点的灰度值Pixel_L和Pixel_R加权均得到,即Pixel=k*Pixel_L+(1-k)*Pixel_R。其中k是可调因子。通常情况下,0<k<1,即在重叠区域中,沿图像1向图像2的方向,k由1渐变为0,从而实现重叠区域的平滑拼接。为使图像重叠区域中的点与两幅图像建立更大的相关性,令k=d1/(d1+d2),其中d1,d2分别表示重叠区域中的点到两幅图像重叠区域的左边界和右边界的距离,即用公式Pixel=d1/(d1+d2)*Pixel_L+d2/(d1+d2)*Pixel_R,进行缝合线处理。

本算法主要包括两个部分:

  • 拼接前对图像1的灰度值向图像2一次线性拟合;

  • 匹配后的图像1和图像21进行拼接。主要算法及说明如下:

% 对灰度图像进行调整
[M1 N1 dim] = size(img1);
[M2 N2 dim2] = size(img2);%获取图像1和2的行列号及灰度值
%自动调整灰度
if exist('adjColor','var') &&adjColor == 1
    radius = 2;
    x1ctrl = matchLoc1(corrPtIdx,1);
    y1ctrl = matchLoc1(corrPtIdx,2);
    x2ctrl = matchLoc2(corrPtIdx,1);
    y2ctrl = matchLoc2(corrPtIdx,2); %获取图像1和2 特征点的位置
    ctrlLen = lenth(corrPtIdx);%获取匹配的特征点的个数
    s1 = zeros(1,ctrlLen);
    s2 = zeros(1,ctrlLen);%生成两个2维矩阵,分别用于存储各特征点的灰度值
%分别取两幅图像四周点灰度值
    for color = 1:dim
        for p = 1:ctrlLen
            left = round(max(1,x1ctrl(p)-radius));
            right = round(min(N1,left+radius+1));
            up = round(max(1,y1ctrl(p)-radius));
            down = round(min(M1,up+radius+1));
            s1(p) = sum(sum(img1(up:down,left:right,color))); 
        end
        for p = 1:ctrlLen
            left = round(max(1,x2ctrl(p)-radius));
            right = round(min(N2,left+radius+1));
            up = round(max(1,y2ctrl(p)-radius));
            down = round(min(M2,up+radius+1));
            s2(p) = sum(sum(img2(up:down,left:right,color)));
        end
%采用直线线性拟合出图像1与图像2之间的灰度值关系
        sc = (radius*2+1)^2*ctrlLen;
        adjcoef = polyfit(s1/sc,s2/sc,1);
%使用拟合出的直线方程改变图像1的灰度值,使得图像1的灰度整体趋向于图像2
        img1(:,:,color) = img1(:,:,color)*adjcoef(1)+adjcoef(2);
    end
end
% 进行拼接
pt = zeros(3,4);
pt(:,1) = H*[1;1;1];
pt(:,2) = H*[N2;1;1];
pt(:,3) = H*[N2;M2;1];
pt(:,4) = H*[1;M2;1];
x2 = pt(1,:)./pt(3,:);
y2 = pt(2,:)./pt(3,:);%生成3*4矩阵,存储图像2经过变换后的上边界和左边界
%确定图像1和图像2拼接位置,以图像1左上角为基准坐标原点
up = round(min(y2)); %获取图像2上顶点
Yoffset = 0; %图像1上顶点
if up <= 0
    Yoffset = -up+1;
    up = 1;
end
left = round(min(x2)); %获取图像2左顶点
Xoffset = 0;%图像1左顶点
if left<=0
    Xoffset = -left+1;
    left = 1;
end
[M3 N3 dim3] = size(img21); %获取图像21的大小
%图像拼接输出
imgout(up:up+M3-1,left:left+N3-1,:) = img21;
%图像1放置在图像21上面
imgout(Yoffset+1:Yoffset+M1,Xoffset+1:Xoffset+N1,:) = img1;
end

三、实验结果

(1)普通照片

拼接前

拼接后

(2)无人机照片

拼接前

拼接后

四、结论

经过本次研究发现,基于SIFT图像拼接效果较好,但是从最后得到的结果图中可以看出仍然存在一些问题。

  • 对于两幅光照或色彩差异较大的图像,仅仅消除可见拼接缝是不够的,还是会有明显的过渡带现象,而且拼接图像看起来也不真实

  • 将该算法运用到无人机影像拼接中发现,此次拼接仍存在明显的拼接痕迹。我们认为是找到的特征点存在一定的误差,此外还受到原本影像拍摄环境等拍摄因素的影响,虽然拼接后两张照片光照和色度基本上很匹配,但是存在明显拼接痕迹。

后续代码将会公开到资源中去,供大家交流学习:)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193445.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(一)Spring源码解析:容器的基本实现

一、Spring的整体架构 Spring的整体架构图如下所示&#xff1a; 二、容器的基本实现 2.1> 核心类介绍 2.1.1> DefaultListableBeanFactory DefaultListableBeanFactory是整个bean加载的核心部分&#xff0c;是Spring注册及加载bean的默认实现。 XmlBeanFactory集成自…

【FLASH存储器系列十四】固态硬盘结构和FTL初探

固态硬盘是一种典型的nand flash产品应用。与传统硬盘相化&#xff0c;固态硬盘内部没有移动的机械磁头&#xff0c;而是由固态电子存储芯片&#xff08;闪存芯片&#xff09;阵列级联组成&#xff0c;下图给出了固态硬盘的内部组成。现阶段&#xff0c;几乎所有基于闪存的固态…

ASP.NET Core+Element+SQL Server开发校园图书管理系统(三)

随着技术的进步&#xff0c;跨平台开发已经成为了标配&#xff0c;在此大背景下&#xff0c;ASP.NET Core也应运而生。本文主要基于ASP.NET CoreElementSql Server开发一个校园图书管理系统为例&#xff0c;简述基于MVC三层架构开发的常见知识点&#xff0c;前两篇文章简单介绍…

Nvidia深度学习环境安装

深度学习大型模型训练和部署&#xff0c;需要使用GPU&#xff0c;使用Pytorch、Tensorflow等深度学习框架之前需要安装驱动环境,本文系统环境&#xff1a;ubuntu22.04系统&#xff0c;四张3090显卡安装显卡驱动下载&#xff1a;选择显卡类型&#xff0c;下载驱动驱动下载路径&a…

Wireshark解析协议不匹配

Wireshark解析协议不匹配 1、问题 现有TLS/SSL over TCP的客户端、服务端相互通信&#xff0c;其中&#xff0c;服务端监听TCP端口6000。 使用tcpdump抓包6000端口&#xff0c;生成pcap文件6000.pcap&#xff1a; 使用Wireshark打开6000.pcap&#xff0c;显示如下&#xff1…

Hive(番外):Hive可视化工具IntelliJ IDEA

1 Hive CLI、Beeline CLI Hive自带的命令行客户端 优点&#xff1a;不需要额外安装 缺点&#xff1a;编写SQL环境恶劣&#xff0c;无有效提示&#xff0c;无语法高亮&#xff0c;误操作几率高 2 文本编辑器 Sublime、Emacs 、EditPlus、UltraEdit、Visual Studio Code等 有…

基于Seam Carving实现图像的重定位 附完整代码

相比于算法目标的复杂&#xff0c;算法步骤却异常的简单&#xff0c;下面具体介绍利用 SeamCarving 算法进行图像剪裁的步骤&#xff1a;1.计算图像中每个像素的“重要程度”&#xff08;能量&#xff09;&#xff0c;生成能量图。在绝大多数情况下&#xff0c;我们可以做出如下…

【string 类的使用方法(总结)】

1. 为什么学习string类&#xff1f; C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需要…

采用NVIDIA Jetson Orin NX 系统的视觉边缘计算机

边缘计算机采用NVIDIA Jetson Orin NX模块化系统和高带宽图像采集卡&#xff0c;用于实时图像采集计算和人工智能处理。虹科的合作伙伴Gidel是一家专注于高速图像采集和处理的以色列科技公司&#xff0c;今天宣布新的NVIDIA Jetson Orin NX™ 16GB模块化系统(SoM)将被添加到Gid…

SpringSecurity配置及使用

Spring Security 是针对Spring项目的安全框架&#xff0c;也是Spring Boot底层安全模块默认的技术选型&#xff0c;他可以实现强大的Web安全控制&#xff0c;对于安全控制&#xff0c;我们仅需要引入spring-boot-starter-security 模块&#xff0c;进行少量的配置&#xff0c;即…

什么是渲染农场,渲染农场一般怎么收费?

对于用3D软件创作效果图或影视动画的艺术家们来说&#xff0c;应该对渲染农场并不陌生&#xff0c;但是对于初入CG行业的人来说&#xff0c;看到网上很多人说渲染农场&#xff0c;肯定会疑惑&#xff0c;什么是渲染农场&#xff1f;渲染农场也叫“分布式并行集群计算系统”&…

【6】【vue3+elementplus+springboot】 管理系统 【前后端实践】

第一部分&#xff1a; elementplus官网&#xff1a;一个 Vue 3 UI 框架 | Element Plus (element-plus.org) 1、安装elementplus npm install element-plus --save查看package.json中存在依赖表示成功安装 2、引入elementplus import ElementPlus from element-plus import …

论文解读 - 城市自动驾驶车辆运动规划与控制技术综述 (第5部分,完结篇)

文章目录&#x1f697; V. Vehicle Control&#xff08;车辆控制&#xff09;&#x1f534; A. Path Stabilization for the Kinematic Model&#xff08;基于运动学模型的路径稳定&#xff09;&#x1f7e5; 1&#xff09;Pure Pursuit&#xff08;纯追踪&#xff09;&#x1…

H3C SecParh堡垒机任意用户登录与远程执行代码漏洞

H3C SecParh堡垒机任意用户登录与远程执行代码漏洞1.H3C SecParh堡垒机任意用户登录漏洞1.1.漏洞描述1.2.漏洞影响1.3.漏洞复现1.3.1.登录页面1.3.2.构建URL1.4.总结2.H3C SecParh堡垒机远程命令执行漏洞2.1.漏洞描述2.2.漏洞影响2.3.漏洞复现2.3.1.登录页面2.3.2.构建URL2.4.总…

python-pptx 操作PPTx幻灯片文件删除并替换图片

python-pptx 操作PPTx幻灯片文件删除并替换图片 作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 一、原理 通过查找ppt中的图片指纹替换 二、操作流程 原始ppt如下&#xff1a; 根据…

[单片机] MCU串口发送C方案优化

应用场景&#xff1a; 主频不高非操作系统的单片机&#xff0c;需要在while循环中发送 数据到上位机&#xff0c;当数据较长时&#xff0c;会让发送的过程会让其他操作有卡顿感。为了解决这个问题&#xff0c;需采用一种方法&#xff1a;在每次大循环中只发一个字节数据&#x…

HTML5+CSS3(一)-全面详解(学习总结---从入门到深化)

目录 ​编辑 第一个前端程序 学习效果反馈 前端工具的选择与安装 前端常见开发者工具 浏览器 VSCode中文语言包安装&#xff1a; 学习效果反馈 VSCode开发者工具快捷键 VSCode常用快捷键列表 学习效果反馈 HTML5简介与基础骨架 HTML5的DOCTYPE声明 HTML5基本骨架 html…

Linux(CentOS Stream 9)安装MySQL8.0

mysql8下载链接 链接&#xff1a;https://pan.baidu.com/s/1yBCDbDYUmQWjcM1SdS7Xng 提取码&#xff1a;t37m 上传到服务器上并解压 cd /usr/localtar -xvf mysql-8.0.21-linux-glibc2.12-x86_64.tar.xz解压包重命名为mysql mv mysql-8.0.21-linux-glibc2.12-x86_64 /usr/l…

Linux部署RKNN-toolkit过程以及异常点记录(详细记录)

文章目录Linux部署RKNN-toolkit过程以及异常点记录1.在Linux中安装Miniconda1.1 使用服务器下载Miniconda1.2 安装conda1.3 激活刚安装完成的软件1.4参考博文2.创建并激活Miniconda新环境&#xff08;rknn&#xff09;2.1 创建conda环境&#xff08;命名为rknn&#xff09;2.2 …

做亚马逊、沃尔玛测评自养号大额、退款一定要解决的几个问题?

大家好我是测评龙哥&#xff0c;今天我跟大家说下做亚马逊、沃尔玛测评自养号、退款、lu货、项目需要用到的防关联、防封号环境的一些底层技术原理。这里讲的内容我相信很少有人能掌握&#xff0c;都是一些比较难的IT术技。 如果你现在准备开始做测评是在了解阶段还是已经在做…