implicitly declaring library_no such object available

implicitly declaring library_no such object availableAPAP论文源码中全局单应GH的部分!

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺


前言

论文及源码地址:APAP项目入口
论文精读:【论文精读】As-Projective-As-Possible Image Stitching with Moving DLT

源码用的MDLT code,解压后的文件夹是mdlt
注意,matlab是基于向量优先的!
让我们从main.m开始!

准备工作与全局变量

比较高版本的matlab需要将多线程部分改成如下代码

%poolsize = matlabpool('size');
poolsize = parpool('local');
if poolsize == 0 %if not, we attempt to do it:
    parpool open;
end

全局变量如下,fitfn等是准备好的求全局单应的函数,在文件夹modelspecific中,C1,C2是网格数

%-------------------------
% User defined parameters.
%-------------------------
% Global model specific function handlers.
clear global;
global fitfn resfn degenfn psize numpar
fitfn = 'homography_fit';
resfn = 'homography_res';
degenfn = 'homography_degen';
psize   = 4;
numpar  = 9;

M     = 500;  % Number of hypotheses for RANSAC.
thr   = 0.1;  % RANSAC threshold.

C1 = 100; % Resolution/grid-size for the mapping function in MDLT (C1 x C2).
C2 = 100;

gamma = 0.1; % Normalizer for Moving DLT. (0.0015-0.1 are usually good numbers).
sigma = 8.5;  % Bandwidth for Moving DLT. (Between 8-12 are good numbers).   
scale = 1;    % Scale of input images (maybe for large images you would like to use a smaller scale).

基于全局单应的图像拼接过程

1.读入图像,特征点检测与匹配

采用原作者注释掉的读取自己输入的两张图片形式,具体代码细节及思想见代码注释,下同。

%------------------
% Images to stitch.
%------------------
path1 = 'images/case26/6.JPG';
path2 = 'images/case26/7.JPG';

%-------------
% Read images.
%-------------
fprintf('Read images and SIFT matching\n');tic;
fprintf('> Reading images...');tic;
img1 = imresize(imread(sprintf('%s',path1)),scale);
img2 = imresize(imread(sprintf('%s',path2)),scale);
fprintf('done (%fs)\n',toc);

%--------------------------------------
% SIFT keypoint detection and matching.
%--------------------------------------
fprintf('  Keypoint detection and matching...');tic;
%single(rgb2gray(img1))将img1转换成单精度灰度图,sift固定格式,必须是单精度的
%'PeakThresh':DoG算法的阈值,值越小,检测到的特征点越多
%'edgethresh':消除DoG尺度空间峰值,值越大,检测到的特征点越多
%kp每一列是一个四元组[x,y,s,th],代表一个特征点信息,分别x,y坐标,s为长度空间大小,th指的是主方向
%ds是特征描述子,也就是那个128维的向量,128×特征点数的矩阵
[ kp1,ds1 ] = vl_sift(single(rgb2gray(img1)),'PeakThresh', 0,'edgethresh',500);
[ kp2,ds2 ] = vl_sift(single(rgb2gray(img2)),'PeakThresh', 0,'edgethresh',500);
%vl_ubcmatch:欧式距离匹配,返回匹配矩阵和匹配对间距离
%[matches, scores] = vl_ubcmatch(ds1, ds2) ;
%matches返回的是2*特征点数量矩阵,
%第一行是一幅图中的匹配点索引,第二行是另一幅图匹配点索引
%每一列是一个匹配点对索引,scores是距离
matches   = vl_ubcmatch(ds1,ds2);
fprintf('done (%fs)\n',toc);

2.数据归一化,RANSAC剔除异常值

% Normalise point distribution.
% 数据归一化的作用是方便后面RANSAC剔除错误点,消除干扰,提高精度,简化计算
fprintf('  Normalising point distribution...');tic;
%matches(1,:):匹配点第一行索引
%matches(2,:):另一张图中的匹配点索引
%kp1(1:2,matches(1,:)):提取出匹配点索引的对应横纵坐标
%size(matches,2):取matches的第二维也就是列,共482列,也就是匹配点数目
%ones(1,size(matches,2)):生成1×4821矩阵
%data_orig是6×482,每个列是两个点的[x y 1]
data_orig = [ kp1(1:2,matches(1,:)) ; ones(1,size(matches,2)) ; kp2(1:2,matches(2,:)) ; ones(1,size(matches,2)) ];
%T矩阵为3×3矩阵
%normalise2dpts作用:把一系列的齐次坐标[x y 1]归一化,使得这些点以原点为中心,距离原点均值为sqrt(2)[ dat_norm_img1,T1 ] = normalise2dpts(data_orig(1:3,:));
[ dat_norm_img2,T2 ] = normalise2dpts(data_orig(4:6,:));

%data_norm:6*482
data_norm = [ dat_norm_img1 ; dat_norm_img2 ];
fprintf('done (%fs)\n',toc);

% %展示输入图像
% if size(img1,1) == size(img2,1)    
%     % Show input images.
%     fprintf(' Showing input images...');tic;
%     figure;
%     imshow([img1,img2]);
%     title('Input images');
%     fprintf('done (%fs)\n',toc);
% end

%-----------------
% Outlier removal.前半部分没读懂代码 mutigs文件夹里有该函数
%-----------------
fprintf('Outlier removal\n');tic;
% Multi-GS
%设置随机种子,rand('state',0),相当于C++中的srand(0)
rng(0);
[ ~,res,~,~ ] = multigsSampling(100,data_norm,M,10);
con = sum(res<=thr);
[ ~, maxinx ] = max(con);
%找到匹配度最高的特征点序列,inliers存的是匹配对的索引
inliers = find(res(:,maxinx)<=thr);

if size(img1,1) == size(img2,1)
    % Show results of RANSAC.
    fprintf(' Showing results of RANSAC...');tic;
    figure;
    imshow([img1 img2]);
    %添加新绘图保持原绘图
    hold on;
    %ro是形状:红圈,LineWidth线宽为2
    %data_orig前两行是一个图的匹配点,用红圈画,45行是另一个图的点,红圈画
    plot(data_orig(1,:),data_orig(2,:),'ro','LineWidth',2);
    %+size(img1,2)为了让它在第二张图位置显示
    plot(data_orig(4,:)+size(img1,2),data_orig(5,:),'ro','LineWidth',2);
    
    for i=1:length(inliers)
        %选择对应内点索引的坐标,12行是一幅图,45行是另一幅图,绿圈画
        plot(data_orig(1,inliers(i)),data_orig(2,inliers(i)),'go','LineWidth',2);
        plot(data_orig(4,inliers(i))+size(img1,2),data_orig(5,inliers(i)),'go','LineWidth',2);
        %14行对应横坐标矩阵,25行对应纵坐标矩阵,绿线相连
        plot([data_orig(1,inliers(i)) data_orig(4,inliers(i))+size(img1,2)],[data_orig(2,inliers(i)) data_orig(5,inliers(i))],'g-');
    end
    title('Ransac''s results');
    fprintf('done (%fs)\n',toc);
end

3.计算全局单应,获取拼接图大小,拼接

%-----------------------
% Global homography (H).计算全局单应
%-----------------------
fprintf('DLT (projective transform) on inliers\n');
% Refine homography using DLT on inliers.
fprintf('> Refining homography (H) using DLT...');tic;
%feval调用参数中fitfn函数,参数为data_norm(:,inliers),即归一化后数据内点索引所在的列
[ h,A,D1,D2 ] = feval(fitfn,data_norm(:,inliers));
%上一步处理之后要再处理回去
Hg = T2\(reshape(h,3,3)*T1);%Hg是全局单应矩阵
fprintf('done (%fs)\n',toc);

%----------------------------------------------------
% Obtaining size of canvas (using global Homography).
%----------------------------------------------------
fprintf('Canvas size and offset (using global Homography)\n');
fprintf('> Getting canvas size...');tic;
%获得拼接图大小,左图不变,右图单应变换
% Map four corners of the right image.
%由于求得的H 是将左图映射到右图,
%即 H*x_left = x_right,所以 x_left = inv(H) * x_right.
%取右图的四个顶点的齐次坐标 分别作为 x_right 的值
%以img1左顶点为坐标源点,得到新的四个顶点坐标:TL, BL, TR, BR
TL = Hg\[1;1;1];%inv(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, ch)
% 投影面的 宽,通过最大的x()-最小的x()+1
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;
fprintf('done (%fs)\n',toc);

% Offset for left image.确定左图的偏移量off,即左图img1 左顶点 在画布坐标系中的 坐标
fprintf('> Getting offset...');tic;
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 ];
fprintf('done (%fs)\n',toc);

%--------------------------------------------
% Image stitching with global homography (H).
%--------------------------------------------
% Warping source image with global homography 
fprintf('Image stitching with global homography (H) and linear blending\n');
fprintf('> Warping images by global homography...');tic;
%创建一个拼接图的空画布
warped_img1 = uint8(zeros(ch,cw,3));
%将左图按照左图偏移off放到画布上
warped_img1(off(2):(off(2)+size(img1,1)-1),off(1):(off(1)+size(img1,2)-1),:) = img1;
%调用imagewarping.cpp,实现warp
warped_img2 = imagewarping(double(ch),double(cw),double(img2),Hg,double(off));
%c++中维度变了,变回matlab所需维度
warped_img2 = reshape(uint8(warped_img2),size(warped_img2,1),size(warped_img2,2)/3,3);
fprintf('done (%fs)\n',toc);

在这之后我添加了单张图放在画布上的结果,以及融合之前的结果

%--------------------------------------------
% 显示单独放在画布上的两张图和融合前的拼接图
%--------------------------------------------
%得到的warped_img1,warped_img2是单独放在整个画布上的
figure;
imshow(warped_img1);
title('warpedimg1');
figure;
imshow(warped_img2);
title('warpedimg2');

output_canvas(:,:,1) = warped_img1(:,:,1)+warped_img2(:,:,1);
output_canvas(:,:,2) = warped_img1(:,:,2)+warped_img2(:,:,2);
output_canvas(:,:,3) = warped_img1(:,:,3)+warped_img2(:,:,3);
output_canvas = uint8(output_canvas);

figure;
imshow(output_canvas);
title('output_canvas');

融合前的效果:
在这里插入图片描述
可见融合是为了消除两张拼接图光照不同的影响。

4.加权融合

% Blending images by simple average (linear blending)
fprintf('  Homography linear image blending (averaging)...');tic;
linear_hom = imageblending(warped_img1,warped_img2);
fprintf('done (%fs)\n',toc);
figure;
imshow(linear_hom);
title('Image Stitching with global homography');

imageblending.m:

function output_canvas = imageBlending(warped_img1,warped_img2)
    %本函数作用:加权平均融合
    
    %将输入warp图形二值化并填充孔
    w1 = imfill(im2bw(uint8(warped_img1), 0),'holes');
    w2 = imfill(im2bw(uint8(warped_img2), 0),'holes');
    
    %转换为灰度图
    w1 = mat2gray(w1);
    w2 = mat2gray(w2);
    
    %注意转换类型
    %matlab处理图像一定先将图像转换为double,im2double
    %1 有些函数支持double型,而不支持uint8的数据类型,所以要转换
    %2 精度问题了,因为uint8进行数据处理的时候,容易造成数据溢出或精度不够。
    warped_img1 = double(warped_img1);
    warped_img2 = double(warped_img2);
    %每个维度根据两张图的二值化灰度图进行融合,主要是处理两张图亮度不同
    %注意都是矩阵运算: .*,./ 点乘点除
    output_canvas(:,:,1) = ((warped_img1(:,:,1).*w1)+(warped_img2(:,:,1).*w2))./(w1+w2);
    output_canvas(:,:,2) = ((warped_img1(:,:,2).*w1)+(warped_img2(:,:,2).*w2))./(w1+w2);
    output_canvas(:,:,3) = ((warped_img1(:,:,3).*w1)+(warped_img2(:,:,3).*w2))./(w1+w2);
    %最后转换回uint8
    output_canvas = uint8(output_canvas);

融合之后的结果:
在这里插入图片描述
消除了光照带来的影响,但是没对齐。

总结

本章讲述了用matlab实现全局单应Global homography的过程及源码分析,本章并不算论文APAP中的部分,而是用来对比APAP方法的优点的,那么我们将在下一章重点讲解APAP的实现原理及过程,欢迎对图像拼接领域的感兴趣的朋友们讨论!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/190475.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • oracle分页的方法,oracle分页[通俗易懂]

    oracle分页的方法,oracle分页[通俗易懂]Oracle的oracle分页oracle的分页一共有三种方式方法一根据rowid来分SELECT*FROMEMPWHEREROWIDIN(SELECTRIDFROM(SELECTROWNUMRN,RIDFROM(SELECTROWIDRID,EMPNOFROMEMPORDERBYEMPNODESC)WHEREROWNUM<=((curre…

    2022年5月8日
    212
  • 【网盘搭建】使用Rclone挂载Google Drive扩容服务器存储,实现网盘无限容量[通俗易懂]

    【网盘搭建】使用Rclone挂载Google Drive扩容服务器存储,实现网盘无限容量[通俗易懂]一,前言1,Rclone是什么Rclone是一个开源的命令行程序,用于管理云存储上的文件。它是云供应商Web存储界面的功能丰富的替代方案。超过50种云存储产品支持Rclone,包括S3对象存储,GoogleDrive,OneDrive等业务和消费者文件存储服务以及标准传输协议。2,它能用来干嘛可以备份(和加密)文件到云存储。从云存储还原(和解密)文件。将云数据镜像到其他云服务或本地。将数据迁移到云,或在云存储供应商之间迁移。将多个加密的,缓存的或多样化的云存储作为磁盘挂载。3,项目地址Gith

    2022年7月16日
    43
  • pycharmhtml插件_pycharm官方中文插件

    pycharmhtml插件_pycharm官方中文插件一、常用配置一、设置文件字符编码二、设置文件模板三、设置文字大小四、修改行数和方发线五、关闭应用更新二、常用插件RainbowCSV将CSV的不同的列用不同的颜色标出RainbowBrackets将每对匹配的括号都变成彩色的IndentRainbow将索引变成彩色CodeGlance在右边生成代码缩略图MaterialTheme不同风格的主题Chinese(Simplified)LanguagePack中文语言包Ke

    2025年7月8日
    0
  • 【11】进大厂必须掌握的面试题-持续集成面试

    Q1。持续集成是什么意思? 我将建议您通过对持续集成(CI)进行小的定义来开始此答案。这是一种开发实践,要求开发人员每天多次将代码集成到共享存储库中。然后,每个签入均由自动构建进行…

    2020年10月20日
    321
  • makefile 编译参数_gcc使用说明

    makefile 编译参数_gcc使用说明gcc编译源文件共有4个过程,预处理、编译、汇编、链接。预处理:命令:gcc-Etest.c-otest.i(-o后面指定生成文件的命名)过程:展开宏定义(#define),处理编译条件指令(#if#ifndef等),插入引用的头文件(#include),删除注释,添加行号和文件标识。结果:生成.i文件,一般的文本编辑器都能打开编译:命令:gcc-Ste…

    2022年10月13日
    0
  • android之ListView的Adapter使用

    在做一个小练习的时候,又遇到了Adapter,才发现以前没有对它进行过记录现在介绍一下:其实Adapter就是数据和视图之间的桥梁,数据在adapter中做处理,然后显示到ListView上面Adapter有很多种,有ArrayAdapter, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ListAdapter,Resource

    2022年3月10日
    48

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号