基于SIFT的多图像多方位拼接(不涉及相对旋转与缩放)

这是一个高中同学Q我让我帮他解决的一个问题,大意就是对飞机拍摄得到的矫正后图像进行拼接。opencv里有相应的实现(cv2.Stitcher_create),但是我试了一下似乎只能左右拼接,而且我没用过opencv,所以想用matlab做,然后python调用就可以了。

以下为思路:

输入N个图像(为加快速度进行下采样),对每个图像进行特征点检测(getFeatures),获得loc和des,loc为图像每个特征点的坐标。并把每个图像的loc和des放入元组(cell)中。

同样设立一个n*n的元组,用来储存一个图像和另一个图像的匹配映射matched。

循环两次计算元组后(对称矩阵,存储一半就可以),每次找到元组存储的映射点数最多的个数(matched(i)=j ;若j为0 则表明图像A的第i个点在B无对应点,否则为B的第j个点  A的第i个特征点的坐标为loc(i,1),loc(i,2)),假设match{i,j}中映射点最多,那么就先把第i个图像和第j个图像进行拼接(stitch.m),得到新图像k。i和j再之后不再进行访问,所以 在存储各个图像的元组I、元组loc和元组des中,分别把第n-1个图像的I、loc、des覆盖到i,把第n个覆盖到j,并把第n-1个赋值为新图像的数据。然后n递减。由于我已经晕了,所以二维元组match直接全部重新计算了。

%分别求1-n的loc 和des
%分别求每两个图的match
%对match中的匹配点个数进行排序
%拼接匹配点最多的两个图像 得到新图像 代替原来的图像
%重复 直到只剩一张
%每次迭代 n-1
%每次提出两个放在最后 把合成的放在第n-1
clear
clc
close all
n=4;%一共多少个图片
I1=imread('1.jpg');
I2=imread('2.jpg');
I3=imread('3.jpg');
I4=imread('4.jpg');
I=cell(1,n);%用元祖存储一系列图像
p=0.5;%压缩比例
I{1}=double(rgb2gray(imresize(I1,p)));
I{2}=double(rgb2gray(imresize(I2,p)));
I{3}=double(rgb2gray(imresize(I3,p)));
I{4}=double(rgb2gray(imresize(I4,p)));
des=cell(1,n);
loc=cell(1,n);
for i=1:n
    [des{i},loc{i}] = getFeatures(I{i});
end
    matched=cell(n,n);%n*n元组
    match_num=zeros(n,n);
while n>1

    for i =1:n
        for j=1:n
            if i<j
                matched{i,j}=match(des{i},des{j});
                match_num(i,j)=sum(sum(matched{i,j}~=0));%统计每个匹配的个数
            end
        end
    end
    max_num=0;
    max_i=0;
    max_j=0;
    for i=1:n
        for j=1:n
            if match_num(i,j)>max_num
                max_i=i;
                max_j=j;
                max_num=match_num(i,j);
            end
        end
    end
    %获得匹配点最多的两个图片的下标 max_i和max_j
    I_new=stitch(I{max_j},I{max_i},loc{max_j},loc{max_i},matched{max_i,max_j});
    figure,imshow(uint8(I_new))
    I{max_i}=I{n-1};%n-1和i交换
    loc{max_i}=loc{n-1};
    des{max_i}=des{n-1};
    I{max_j}=I{n};
    loc{max_j}=loc{n};
    des{max_j}=des{n};
    I{n-1}=I_new;
    [des{n-1},loc{n-1}]=getFeatures(I{n-1});
    n=n-1;
end

(代码中对j,i进行stitch而不是i,j, 是因为拼接的新图像的下标数值大且面积大,最宜用小图像拼接到稍微大的图像)

两个图像拼接的函数stitch.m:

首先获得两个图像的长宽:h1、h2、d1、d2

考虑最大可能,把图像I1分别向四周拓宽max(d1,d2)个像素,并存为result矩阵中。

 

调用function map=getmap(matched) 对输入的matched进行调整,获得一个x*2维度的map矩阵,x为matched中对应点的个数,第一列为图像I1的点序号,第二列为图像I2的点序号。

之后分别求map中第一列的点和 对应的第二列的点的x坐标的偏移pos_x和y坐标偏移pos_y的均值,也就是I2相对于I1的偏移。

result按如下方式计算:

其中,D为权值,应在不同区域获得不同的取值,本例使用越靠近I1的D取值越大,越靠近I2的D取值越小的相邻元素等比矩阵mask实现。(代码中mask(i,j)越靠近I2权值越大。mask的取值取决于重叠部分的大小以及位移的方向)

其中,mask也即重叠部分的长宽可按如下方法获得:

左上角坐标可以通过遍历I2,在result中找到第一个不为0的点,就是重叠部分的左上角下标I2中下标与result的对应关系为,result(dev_x+i,dev_y+j)=I2(i,j) 其中dev_x/y为相对于result的偏移(之前的pos_x/y为I2相对于I1):

                      dev_x=max(h2,d2)+pos_x; %相对于扩展后的I1(result)的
                      dev_y=max(h2,d2)+pos_y; 

右下角直接计算:

mask_i_max=h1-pos_x+1; mask_j_max=d1-pos_y+1;

(此时result只有I1图像)

遍历图二,判定是否该点在重叠范围内,并且该重叠范围内的点的灰度值不为0。若不为0,则由之前的mask计算result,否则,result(i,j)=I2(i,j)。

最后对result裁剪掉全0的行或者列。

(代码中有注释掉的旋转缩放部分,但是好像出错了)

% I1=imread('1.jpg');
% I2=imread('2.jpg');
% I1=double(rgb2gray(I1));
% I2=double(rgb2gray(I2));    
% [des1,loc1] = getFeatures(I1);
% [des2,loc2] = getFeatures(I2);
% matched = match(des1,des2);
%drawMatched(matched,I1,I2,loc1,loc2);
function result=stitch(I1,I2,loc1,loc2,matched)
    map=getmap(matched);
    [h1,d1]=size(I1);
    [h2,d2]=size(I2);
    result=zeros(h1+2*max(h2,d2),d1+2*max(h2,d2));
    result(max(h2,d2)+1:max(h2,d2)+h1,max(h2,d2)+1:max(h2,d2)+d1)=I1;
    pos_x=0;
    pos_y=0;%平移
    for i=1:length(map)
        pos_x=pos_x+loc1(map(i,1),1)-loc2(map(i,2),1);
        pos_y=pos_y+loc1(map(i,1),2)-loc2(map(i,2),2);
    end
    pos_x=round(pos_x/length(map));
    pos_y=round(pos_y/length(map));
    dev_x=max(h2,d2)+pos_x; %相对于扩展后的I1(result)的
    dev_y=max(h2,d2)+pos_y; 


    
    %result(dev_x+1:dev_x+h2,dev_y+1:dev_y+d2)=I2;
    for i =1:h2
        for j=1:d2
            bre=0;
            if result(dev_x+i,dev_y+j)~=0 %在遮罩范围内
                mask_i_min=i;%遮罩在I2内的左上角下标
                mask_j_min=j;
                bre=1;
                break
            end
        end
        if bre==1
            break
        end
    end
    mask_i_max=h1-pos_x+1;
    mask_j_max=d1-pos_y+1;
    mask=getmask(pos_x,pos_y,mask_i_max-mask_i_min,mask_j_max-mask_j_min);
    for i =1:h2
        for j=1:d2
            if i>=mask_i_min && i<=mask_i_max && j>=mask_j_min && j<=mask_j_max && result(dev_x+i,dev_y+j)%在遮罩范围内
                %result(dev_x+i,dev_y+j)=255;
                result(dev_x+i,dev_y+j)=mask(i-mask_i_min+1,j-mask_j_min+1)*I2(i,j)+(1-mask(i-mask_i_min+1,j-mask_j_min+1))*result(dev_x+i,dev_y+j);
            else
                result(dev_x+i,dev_y+j)=I2(i,j);
            end
        end
    end
    %调整
    y_min=1;
    [x_max,y_max]=size(result);
    for x_min=1:x_max
        if sum(result(x_min,:)~=0)
            break
        end
    end
    for y_min=1:y_max
        if sum(result(:,y_min)~=0)
            break
        end
    end

    for x_max=x_max:-1:x_min
        if sum(result(x_max,:)~=0)
            break
        end
    end
    for y_max=y_max:-1:y_min
        if sum(result(:,y_max)~=0)
            break
        end
    end
    result=result(x_min:x_max,y_min:y_max);
end
    %旋转
%     theta=0;
%     p=0;
%     for i=1:length(map)
%         for j=1:length(map)
%             if i~=j
%                 theta=theta+(loc1(map(i,1),1)-loc1(map(j,1),1))/(0.01+loc1(map(i,1),2)-loc1(map(j,1),2)) - ...
%                             (loc2(map(i,2),1)-loc2(map(j,2),1))/(0.01+loc2(map(i,2),2)-loc2(map(j,2),2));
%                 len1=sqrt((loc1(map(i,1),1)-loc1(map(j,1),1))^2+(loc1(map(i,1),2)-loc1(map(j,1),2))^2);
%                 len2=sqrt((loc2(map(i,2),1)-loc2(map(j,2),1))^2+(loc2(map(i,2),2)-loc2(map(j,2),2))^2);
%                 p=p+(len1/len2);
%             end
%         end
%     end
%     theta=theta/(length(map)*length(map)-length(map));
%     p=p/(length(map)*length(map)-length(map));
%     dir=-theta;
%     rotate=atan(-theta)*180/pi;
%     B=zeros(2*h2,2*d2);
%     B(h2+1:2*h2,d2+1:2*d2)=I2;
%     B=imrotate(B,rotate);
%     B(1:h1,1:d1)=I1;
%     imshow(uint8(B));
%     figure,
%     S=imresize(B,p,'nearest');
%     imshow(uint8(S));
%     loc1=uint8(loc1);
%     loc2=uint8(loc2);
%     R=[cos(dir),-sin(dir);sin(dir),cos(dir)];
%     for i=1:length(map)
%         I1(loc1(map(i,1),1),loc1(map(i,1),2))=0;
%         I2(loc2(map(i,2),1),loc2(map(i,2),2))=0;
%     end
%     subplot(121),imshow((I1))
%     subplot(122),imshow((I2))
    
    
    function map=getmap(matched)%返回 二维矩阵 表示点的对应关系
        map=zeros(sum(matched~=0),2);
        k=1;
        for i =1:length(matched)
            if matched(i)~=0
                map(k,2)=i;
                map(k,1)=matched(i);
                k=k+1;
            end
        end
    end
   

    
function mask=getmask(pos_x,pos_y,len_x,len_y) %根据偏移值返回一个m*n的mask  pox>0 poy>0时候 右下为1 左上为0
    if pos_x>1
        d_x=0:1/len_x:1;
    elseif pos_x<-1
        d_x=1:1/(-len_x):0;
    else
        d_x=ones(1,1);
    end
    
	if pos_y>1
        d_y=0:1/len_y:1;
	elseif pos_y<-1
        d_y=1:1/(-len_y):0;
	else
        d_y=ones(1,1);
	end
    
	mask=d_x'*d_y;
end

 

运行:

在百度地图上随便截了几张图:

运行结果如下:

(压缩比例p=0.5)

注:为提高速度和效率  可以在对图像进行下采样代替图像获得特征点,之后得到的平移大小和缩放比例运算后可以得到原图像的平移大小,在对原图像进行平移融合即可。

源代码与sift代码(一年前计算机视觉课上下的,无法获得来源)已上传至百度网盘:

链接:https://pan.baidu.com/s/1ax12UNZhsrSe2-wPyrnwBQ 
提取码:14q0 

zip中.m文件:stitch和multstitch为本例代码 run和process为其他项目代码(无用),其他都为sift代码。

 


 

 

 

 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值