AANAP代码学习

2023-11-01

Code:YaqiLYU/AANAP
Paper:Adaptive As-Natural-As-Possible Image Stitching

1、加载并显示图片
加载两幅图片:img1、img2,把img2大小resize为img1大小。

%% Global options
% 0 - Bilinear interpolation, implementation by MATLAB锛宻lower but better-->双线性插值
% 1 - Nearest neighbor interpolation,implementation by C++, Faster but worse---->最邻近插值
fast_stitch = 1;    
img_n = 2;  % only support two image stitching
in_name = cell(img_n,1);
in_name{1} = 'images/case26/img04.JPG';
in_name{2} = 'images/case26/img05.JPG';
img_n = size(in_name, 1);

gamma = 0;
sigma = 12.5;

%% load and preprocessing
I = cell(img_n, 1);
for i = 1 : img_n
    I{i} = imread(in_name{i});
end

max_size = 1000 * 1000;
imgw = zeros(img_n, 1);
imgh = zeros(img_n, 1);

for i = 1 : img_n
    if numel(I{i}(:, :, 1)) > max_size
        I{i} = imresize(I{i}, sqrt(max_size / numel(I{i}(:, :, 1))));
    end

    imgw(i) = size(I{i}, 2);
    imgh(i) = size(I{i}, 1);
end

img1 = I{1};
img2 = I{2};
img2 = imresize(img2,size(img1,1)/size(img2,1));

figure(4),
imshow(img1,[]);
pause(0.3);
figure(5),
imshow(img2,[]);
pause(0.3);

2、变量初始化

%% User defined parameters for APAP
clear global;
global fitfn resfn degenfn psize numpar
fitfn = 'homography_fit';   %计算Global H
resfn = 'homography_res';
degenfn = 'homography_degen';
psize   = 4;
numpar  = 9;

M     = 500;
thr_g = 0.1;    %RANSAC threshold

if fast_stitch
    C1    = 100;    %C1C2为分块大小
    C2    = 100;
else
    C1    = 200;
    C2    = 200;
end

3、SIFT特征检测与匹配

[ kp1,ds1 ] = vl_sift(single(rgb2gray(img1)),'PeakThresh', 0,'edgethresh',500);
[ kp2,ds2 ] = vl_sift(single(rgb2gray(img2)),'PeakThresh', 0,'edgethresh',500);
[match_idxs, scores] = vl_ubcmatch(ds1,ds2);
f1 = kp1(:,match_idxs(1,:));
f2 = kp2(:,match_idxs(2,:));

kp1:img1的特征点(本例中kp1:4x2067,既找到了2067个特征点)
这里写图片描述

kp2:img2的特征点(本例中kp2:4x1779,既找到了1779个特征点)
这里写图片描述

match_idxs:img1,img2匹配的特征点的索引:(本例中match_idxs:2x534,既找到了534个匹配对)
这里写图片描述

[F,D] = VL_SIFT(I)
F为特征点,D为描述子。

%   Each column of F is a feature frame and has the format [X;Y;S;TH], where 
%   X,Y is the (fractional) center of the frame, S is the scale and TH is
%   the orientation (in radians).

%   [F,D] = VL_SIFT(I) computes the SIFT descriptors [1] as well. Each
%   column of D is the descriptor of the corresponding frame in F. A
%   descriptor is a 128-dimensional vector of class UINT8.

4、匹配点归一化,用门限值 thr_g = 0.1 删除RANSAC的Outliner

%% Normalise point distribution and Outlier removal with Multi-GS RANSAC.
% (x1;y1;1;x2;y2;1)
data_orig = [ kp1(1:2,match_idxs(1,:)) ; ones(1,size(match_idxs,2)) ;
              kp2(1:2,match_idxs(2,:)) ; ones(1,size(match_idxs,2)) ];
[ dat_norm_img1,T1 ] = normalise2dpts(data_orig(1:3,:));
[ dat_norm_img2,T2 ] = normalise2dpts(data_orig(4:6,:));
data_norm = [ dat_norm_img1 ; dat_norm_img2 ];

% Multi-GS
% rng(0);
[ ~,res,~,~ ] = multigsSampling(100,data_norm,M,10);
con = sum(res<=thr_g);
[ ~, maxinx ] = max(con);
inliers = find(res(:,maxinx)<=thr_g);%找到匹配度最高的特征点序列,inliers存的是匹配对的索引

data_orig:齐次坐标下所有匹配特征点的组合。(本例中data_orig:6x534,对应534个匹配对的坐标–>x1,y1,1;x2,y2,1)
这里写图片描述
[newpts, T] = normalise2dpts(pts):归一化函数
作用:把一系列的齐次坐标[x y 1]归一化,使得这些点以原点为中心,距离原点均值为sqrt(2)。


function [newpts, T] = normalise2dpts(pts)

    if size(pts,1) ~= 3
        error('pts must be 3xN');
    end

    % Find the indices of the points that are not at infinity
    finiteind = find(abs(pts(3,:)) > eps);%找出非无穷远点的序号

    if length(finiteind) ~= size(pts,2)
        disp('Some points are at infinity');
    end

    % For the finite points ensure homogeneous coords have scale of 1
    pts(1,finiteind) = pts(1,finiteind)./pts(3,finiteind);
    pts(2,finiteind) = pts(2,finiteind)./pts(3,finiteind);
    pts(3,finiteind) = 1;

    c = mean(pts(1:2,finiteind)')';            % Centroid of finite points (找出所有点的中值)
  % c =
  %368.3553
  %434.4607
    newp(1,finiteind) = pts(1,finiteind)-c(1); % Shift origin to centroid.
    newp(2,finiteind) = pts(2,finiteind)-c(2); % 其他特征点到中值点的偏移量

    dist = sqrt(newp(1,finiteind).^2 + newp(2,finiteind).^2);%其他特征点到中值点的距离
    meandist = mean(dist(:));  % Ensure dist is a column vector for Octave 3.0.1其他特征点到中值点的平均距离

    scale = sqrt(2)/meandist;

    T = [scale   0   -scale*c(1)
         0     scale -scale*c(2)
         0       0      1      ];

    newpts = T*pts;

end

T的作用相当于:
x’ = scale(x-c(1));
y’ = scale(y- c(2));

data_norm :归一化后的匹配点矩阵
这里写图片描述

inliers:最佳匹配对索引:(本例中inliers:511x1,对应511个内点的索引)

RANSAC算法流程:
这里写图片描述
详情看slids:
Advances in Computer Vision
Lecture 9
Mid level vision:
Stereo, Homographies, RANSAC

5、通过内点计算Global H

%% Global homography (H) again.
[ Hl,A,D1,D2 ] = feval(fitfn,data_norm(:,inliers));
Hg = T2\(reshape(Hl,3,3)*T1);
Hg = Hg / Hg(3,3)

Hg =

1.3326    0.0151 -314.6591
0.2190    1.2556 -104.2045
0.0006    0.0000    1.0000

6、求Global similarity transformation—->S

%% Compute Global similarity
S = ransac_global_similarity(data_norm(:,inliers),data_orig(:,inliers),img1,img2);
S = T2\(S*T1)

先看看相似变换:图像的等距变换,相似变换,仿射变换,射影变换及其matlab实现
这里写图片描述
上述变换可以转换为:
这里写图片描述

对应代码:

for idx = 1:size(x,2)
        A = [A; x(idx) -y(idx) 1 0;
                y(idx)  x(idx) 0 1];

        b = [b;x_(idx);
               y_(idx)];
    end
    beta = A\b;

    S_segment{i} = [beta(1) -beta(2) beta(3);
                    beta(2)  beta(1) beta(4);
                         0        0       1];

ransac_global_similarity(data,data_orig,img1,img2)函数:
作用:查找旋转角度最小的相似矩阵

function S = ransac_global_similarity(data,data_orig,img1,img2)
thr_l = 0.001;
M = 500;

figure(1);
imshow([img1 img2]);
title('Ransac''s results');
hold on;
plot(data_orig(1,:),data_orig(2,:),'go','LineWidth',2);
plot(data_orig(4,:)+size(img1,2),data_orig(5,:),'go','LineWidth',2);
hold on;
pause(0.5)

%通过门限值thr_l获取内点inliers
for i = 1:20
    [ ~,res,~,~ ] = multigsSampling(100,data,M,10);
    con = sum(res<=thr_l);
    [ ~, maxinx ] = max(con);
    inliers = find(res(:,maxinx)<=thr_l);
    if size(inliers) < 50
        break;
    end
    data_inliers = data(:,inliers);

    x  = data_inliers(1,:); 
    y  = data_inliers(2,:); 
    x_ = data_inliers(4,:);     
    y_ = data_inliers(5,:);

    A = [];
    b = [];

    for idx = 1:size(x,2)
        A = [A; x(idx) -y(idx) 1 0;
                y(idx)  x(idx) 0 1];

        b = [b;x_(idx);
               y_(idx)];
    end
    beta = A\b;

    %通过inliers计算相似矩阵
    S_segment{i} = [beta(1) -beta(2) beta(3);
                    beta(2)  beta(1) beta(4);
                         0        0       1];
    %计算旋转角度                         
    theta(i)     = atan(beta(2)/beta(1));

    clr = [rand(),0,rand()];
    plot(data_orig(1,inliers),data_orig(2,inliers),...
         'o','color',clr,'LineWidth',2);
    plot(data_orig(4,inliers)+size(img1,2),data_orig(5,inliers),...
         'o','color',clr,'LineWidth',2);
    hold on;
    pause(0.5);

    %查找outliners,删除内点inliers
    outliers = find(res(:,maxinx)>thr_l);
    data = data(:,outliers);
    data_orig = data_orig(:,outliers);
end

index = find(abs(theta) == min(abs(theta)));
S = S_segment{index};
end

这一段代码对应论文:
这里写图片描述
for i = 1:20
……
end
循环:
i=1时:
这里写图片描述

相似矩阵S:
这里写图片描述
7、计算pano大小

 %% Obtaining size of canvas (using global Homography).%img2映射到canvas的坐标-->H\x2
    TL = Hg\[1;1;1];
    TL = round([ TL(1)/TL(3) ; TL(2)/TL(3) ]);
    BL = Hg\[1;size(img2,1);1];
    BL = round([ BL(1)/BL(3) ; BL(2)/BL(3) ]);
    TR = Hg\[size(img2,2);1;1];
    TR = round([ TR(1)/TR(3) ; TR(2)/TR(3) ]);
    BR = Hg\[size(img2,2);size(img2,1);1];
    BR = round([ BR(1)/BR(3) ; BR(2)/BR(3) ]);

    % Canvas size.
    cw = max([1 size(img1,2) TL(1) BL(1) TR(1) BR(1)]) - min([1 size(img1,2) TL(1) BL(1) TR(1) BR(1)]) + 1;
    ch = max([1 size(img1,1) TL(2) BL(2) TR(2) BR(2)]) - min([1 size(img1,1) TL(2) BL(2) TR(2) BR(2)]) + 1;

    % Offset for left image.
    off = [ 1 - min([1 size(img1,2) TL(1) BL(1) TR(1) BR(1)]) + 1 ;
            1 - min([1 size(img1,1) TL(2) BL(2) TR(2) BR(2)]) + 1 ];

img2**映射前**的TL,BL,TR,BR如下图所示:
这里写图片描述
img2**映射后**的TL,BL,TR,BR:
这里写图片描述
8、把img1框起来

%% Generate anchor points in the boundary,20 in each size, 80 in total
anchor_points = [];
anchor_num = 20;
hx = linspace(1,size(img1,2),anchor_num);
hy = linspace(1,size(img1,1),anchor_num);

for i = 1:anchor_num
    anchor_points = [anchor_points;
                     1, round(hy(i))];    
    anchor_points = [anchor_points;
                     size(img1,2), round(hy(i))];   
    anchor_points = [anchor_points;
                     round(hx(i)), 1];    
    anchor_points = [anchor_points;
                     round(hx(i)), size(img1,1)];
end

将img1用为20*20的圆点框起来的网格
[hx;hy]:

这里写图片描述

这里写图片描述

9、计算权重

  %% Compute weight for Integration
       % (x,y): K_min -> K_1 -> K_2 -> K_max
    Or = [size(img1,2)/2;size(img1,1)/2];
    Ot = Hg\[size(img2,2)/2;size(img2,1)/2;1];
    Ot = [Ot(1)/Ot(3);Ot(2)/Ot(3)];

    % solve linear problem
    k = (Ot(2) - Or(2))/(Ot(1) - Or(1));%斜率
    b = Or(2) - k * Or(1);%截距

    K_min(1) = min([TL(1) BL(1) TR(1) BR(1)]);
    K_max(1) = max([TL(1) BL(1) TR(1) BR(1)]);
    K_1(1) = size(img1,2);
    K_2(1) = K_1(1) + (K_max(1) - K_1(1))/2;%img2投影后的中点横坐标

    K_min(2) = k * K_min(1) + b;
    K_max(2) = k * K_max(1) + b;
    K_1(2) = k * K_1(1) + b;
    K_2(2) = k * K_2(1) + b;

    % Image keypoints coordinates
    Kp = [data_orig(1,inliers)' data_orig(2,inliers)'];

    [ X,Y ] = meshgrid(linspace(1,cw,C1),linspace(1,ch,C2));

    % Mesh (cells) vertices' coordinates.
    Mv = [X(:)-off(1), Y(:)-off(2)];

    % Perform Moving DLT
    fprintf('  Moving DLT main loop...');tic;
    Ht = zeros(size(Mv,1),9);
    Hr = zeros(size(Mv,1),9);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AANAP代码学习 的相关文章

  • 飞书与IAI国际广告奖,协同实现国内营销史上的创新“云终审”

    防疫时期 线下营销活动暂停或无限延期 转型线上迫在眉睫 而想要高效地进行线上远程办公 一套实用而全面的线上协同工具不可或缺 今天的主角 IAI国际广告奖 是由中国传媒大学广告学院与IAI国际广告研究所联合主办的中国大型广告作品案例评选活动
  • 随笔:MySQL 查询事务状态字段说明

    今天一个朋友想查看一下的MySQL层事务提交状态经历的过程 比如我们常说的prapare flush sync commit 几个阶段 但是找了一下发现视乎没有视图可以看到一共看了3个地方 information schema INNODB
  • Elasticsearch实战(十二)---搜索推荐 match_phrase_prefix及fuzzy错误拼写模糊查询

    Elasticsearch实战 搜索推荐 match phrase prefix 文章目录 Elasticsearch实战 搜索推荐 match phrase prefix 1 搜索推荐场景 1 1 准备数据 2 搜索推荐实现 2 1 ma
  • nginx报404 not found错误解决

    一般报404错误都是因为nginx做了伪静态 去除了框架的index php 访问某域名时 去掉index php目录时达到效果一样 如 www test1 index php test2跟www test1 test2效果一致 在vhos
  • stm32flash碰到hex文件出错,读取超慢, 占用内存超多的问题解决

    这个问题是因为sdcc生成的hex的每行的地址并不是排序的好的 有些高的地址在前面 低的地址在后面 这样的话 stm32flash这个hex c并不能处理这个情况 里面有一个逻辑是用来填补0xff的 当后面的地址比前面大 一减得负数 但是变
  • TCP协议详解(三次握手,传输数据,四次挥手)

    首先来了解一下什么是TCP 传输控制协议 简单点来讲TCP它是一种网络通信协议 旨在通过internet发送数据包 TCP是OSI层中的传输层协议 第四层 用于通过传输和确保通过支持网络和internet传递消息来在远程计算机之间创建连接
  • React Native环境及项目配置搭建

    安装RN环境卡了我好久 在网上搜了很多都不全遇到很多坎儿 时至今日我终于装好了 打算写一个详细过程造福大众 也算是对自己总结更深层的记忆 1 首先看官网 React 注意要点 必须要有node javaJDK和AndroidStudio 再
  • iOS 4层结构(iOS技术概要)—— Media 层(二)

    Media层 媒体层提供了图形 音频和视频技术支持 以达到移动设备上极佳的多媒体体验 一 图形技术 高品质图形是iOS应用程序非常重要的一部分 最简单 和最有效 的方法来创建一个应用程序是使用预渲染图片与UI标准控件结合实现系统绘制 然而
  • 如何用git将本地文件放到github上

    1 在github上新建一个仓库 2 使用如下命令操作 前提 本地已安装git 使用git Bash运行如下代码 git init 使本地文件夹成为一个本地git仓库 运行后文件夹下会生成一个 git文件夹 git add 将本地文件夹添加
  • Seata解析-数据源代理DataSourceProxy详解

    本文基于seata 1 3 0版本 前面通过十多篇文章详细介绍了TC端 从这篇文章开始介绍RM RM是资源管理器 资源指的就是数据库 RM主要与分支事务有关 RM会处理业务数据 在 Seata解析 seata部署启动初体验 中 使用了类Da
  • osg学习(五十二)加载的牛模型cow.osg没有纹理 黑色

    1 纹理文件 Images reflect rgb 没有正确加载 2 Android 的gles中没有glTexGen函数 需要通过着色器程序实现 参看C 学习 三三六 球面贴图Sphere mapping 立方体贴图Cube mappin
  • 02黑马数据结构笔记之单向链表搭建(list)

    02黑马数据结构笔记之单向链表搭建 list 1 思路 以STL的容器list类似 将各个数据节点存放在链表当中 实现是靠一个结构体来管理各个数据节点 定义一个节点类型 typedef struct Node 接收任何数据 void dat
  • 远程访问群晖Drive并挂载为电脑磁盘同步备份文件「无需公网IP」

    文章目录 前言 1 群晖Synology Drive套件的安装 1 1 安装Synology Drive套件 1 2 设置Synology Drive套件 1 3 局域网内电脑测试和使用 2 使用cpolar远程访问内网Synology D
  • C语言小游戏——推箱子(基础版)

    推箱子 1 游戏界面 2 游戏说明 3 程序分析 4 整个游戏源代码 1 游戏界面 2 游戏说明 贪吃蛇游戏按键说明 升级版的功能 可以进行通关模式 通过方向键WSAD键或者上下左右键 可以改变人移动方向的改变 3 程序分析 第一部分 绘制
  • 支付宝网页支付交互流程 nest 版

    自己整理了一份支付宝网页支付的交互流程 完全按交互流程响应步骤介绍的代码 效果图 因为平时主要用node开发 所以服务端用的node 框架是 nest 用最精简的代码实现支付功能 1 流程图 为了让下面的交互流程更清楚点 做了一张 简单粗暴
  • ESP32 CAM学习记录 (1) ——安装开发环境及烧录固件至ESP32-CAM开发板(虚拟机开发篇)

    本次开发使用安信可官方提供的开发环境 直接在windows下用虚拟机进行开发 1 搭建开发环境 开发环境连接 https pan baidu com s 1hWJAfeDQbYiD01X6eyqgMw 用 vmware12打开虚拟机 导入安
  • 自然语言处理入门指北 之 one-hot

    自然语言 Natural Language 通常是指一种自然地随文化演化的语言 例如 汉语 英语 日语都是自然语言的例子 与编程语言等为计算机而设的 人造 语言相对 自然语言无法直接被计算机等 理解 在这个前提下 如何让计算机认识 学习乃至
  • vue 的 el-table-infinite-scroll下拉加载

    使用el table infinite scroll 插件 安装插件 npm install save el table infinite scroll 全局引入并注册 main js import elTableInfiniteScrol
  • python基础:字典常用函数和方法

    字典 dictionary dict 字典的每个元素都是由一个key和一个value组成的 键 值 键是唯一的 且键是不可变数据类型 值是可以任意的 数据类型任意 且值可以重复 创建一个字典 dic aa aa的值 bb bb的值 cc c

随机推荐