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的实现原理及过程,欢迎对图像拼接领域的感兴趣的朋友们讨论!

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • word在试图打开文件时遇到错误,检查稳定或驱动器文件权限

    word在试图打开文件时遇到错误,检查稳定或驱动器文件权限查网上说属性—解除锁定,就好了我看很多人也是这问题,这种方案就可以解决。但我的是根本就没有“解除锁定”这一选项。我用的是2013版的word,但可以用office2010打开(我电脑上安装了两个office版本)。而且在其它电脑上office2013可以打开。我的解决方案是用office2010打开后把昨天写的部分删除,发现用office2013可以打开了。然后再从201…

  • php 死链查询,seo网站死链解决方法 死链查询检测工具

    php 死链查询,seo网站死链解决方法 死链查询检测工具死链是指服务器的地址已经改变了.无法找到当前地址位置,包括协议死链和内容死链两种形式。死链出现的原因有网站服务器设置错误;某文件夹名称修改,路径错误链接变成死链等。我们都知道死链对seo排名的危害是非常大的。死链对网站的危害一、有可能会让搜索引擎降权二、用户体验较差死链检测方法:Xenu死链查询工具今天教大家如何使用Xenu死链接检测工具对网站死链接(什么是网站死链)进行处理,有图有真相,轻松四步…

  • 重构什么意思_直接重购

    重构什么意思_直接重购Percona PT-kill重构版(PHP)

  • 如何知道一个网站的后台地址_看我如何攻破LOL钓鱼网站后台查清背后的大量账号被盗号的真相…

    如何知道一个网站的后台地址_看我如何攻破LOL钓鱼网站后台查清背后的大量账号被盗号的真相…说英雄联盟准备出手游,但内测资格一直没公开,有骗子利用这个机会,伪造官方给用户发送带有钓鱼链接的邮件来盗号。.方子就是其中一个受害者,除了他,我也去了英雄联盟的贴吧看了下,确实有很多人收到了这类邮件。由于反馈这事的人比较多,加上我平常也玩LOL,所以整理了下线索,开整。目前一共有两条线索。1.钓鱼邮件:j6****j9@***zol.com2.钓鱼网站:www.iku****.cn首先是发送钓鱼网…

  • Windows&Linux双系统安装流程

    Windows&Linux双系统安装流程注意事项:安装Windows&Linux双系统,最好先安装windows系统,否则可能会出现grub引导覆盖的问题。Window10系统安装1.制作启动盘(优启通链接)https://www.itsk.com/forum.php?mod=viewthread&tid=397875注:U盘尽量用品牌优盘,启动盘软件一定要选择好不然无法识别。优启通、优碟通、大白菜、老毛桃…

  • 程序员接私活的平台(java接私活哪个网站好)

    这里分享一些程序员如何接私活的一些平台~开发邦:https://www.kaifabang.com/码易:https://www.mayigeek.com/开源众包:https://zb.oschina.net/人人开发:http://rrkf.com/程序员客栈:https://www.proginn.com/码市:https://codemart.com/快码众包:https:…

发表回复

您的电子邮箱地址不会被公开。

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