前面已经做了亮度调整,和权重融合
这个图融合处是有重影的
在一个博文《多分辨率拼接算法(继最佳缝合线之后)》中,有一个最佳缝合线的matlab的代码,
我把它改成opencv的一个函数bestlinefusion:
//《图像拼接的改进算法》最佳缝合线算法 图像融合
Mat_<Vec3f> bestlinefusion(Mat_<Vec3f> & A,Mat_<Vec3f>& B,int rdata1)
//function D=bestlinefusion(A,B,rdata1)
{
//先根据之前得到的H矩阵计算重叠区域Rect
//[H,W,k]=size(A);
int H,W;
H=A.rows;W=A.cols;
//rdata1=-118;
//rdata1=fix(-rdata1);
rdata1=-rdata1;
//L=W+1+rdata1;
int L=W+rdata1;
//R=W;
int R=W;
//n=R-L+1;
int n=R-L;
//计算得到重叠区域的差值图像 其实我不懂计算差值图像干嘛 只要计算重叠区域的大小就好了 为什么还要计算差值图 后面又没用到
//Rect=zeros(H,n);
Mat_<float> Rectf=Mat_<float>::zeros(H,n);
#define A(x,y) A(x,y)[0]
#define B(x,y) B(x,y)[0]
//for i=1:H
for(int i=0;i<H;i++){
// for j=L:R
for(int j=L;j<R;j++){
Rectf(i,j-L+1)=A(i,j)-B(i,j-L+1);
//Rectf(i,j-L)=A(i,j)[0]-B(i,j-L+1)[0];
}//end
}//end
//Rectf=uint8(Rectf);//这句要不要呢?
//最终融合图的大小
//rdata1=-118;
//rdata2=3;
int Y=2*W+rdata1+1;
Mat_<Vec3f> D=Mat_<Vec3f>::zeros(H,Y);
//放路径的矩阵
Mat_<float> path=Mat_<float>::zeros(H,n);
//放强度值 每条路径的强度值strength=color^2+geometry
Mat_<float> color=Mat_<float>::zeros(1,n);
Mat_<float> geometry=Mat_<float>::zeros(1,n);
Mat_<float> strength1=Mat_<float>::zeros(1,n);
Mat_<float> strength2=Mat_<float>::zeros(1,n);
float Bxdao;
float Bydao;
float Aydao;
float Axdao;
//计算第一行即初始化的强度值
//for j=L:R
for(int j=L;j<R;j++){
int y=j-L+1;
color(y)=A(1,j)-B(1,y);
if(y==1){
Bxdao=B(1,y+1)+2*B(2,y+1);
Bydao=B(2,y)+2*B(2,y+1);
Aydao=2*A(2,j-1)+A(2,j)+2*A(2,j+1);
Axdao=A(1,j+1)+2*A(2,j+1)-A(1,j-1)-2*A(2,j-1);
geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
strength1(y)=sqrt(color(y))+geometry(y);
path(1,y)=y;
continue;
}//end
if(j==R){
Axdao=A(1,j-1)-2*A(2,j-1);
Aydao=2*A(2,j-1)+A(2,j);
Bxdao=B(1,y+1)+2*B(2,y+1)-B(1,y-1)-2*B(2,y-1);
Bydao=2*B(2,y-1)+B(2,y)+2*B(2,y+1);
geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
strength1(y)=sqrt(color(y))+geometry(y);
path(1,y)=y;
continue;
}//end
Axdao=A(1,j+1)+2*A(2,j+1)-A(1,j-1)-2*A(2,j-1);
Bxdao=B(1,y+1)+2*B(2,y+1)-B(1,y-1)-2*B(2,y-1);
Aydao=2*A(2,j-1)+A(2,j)+2*A(2,j+1);
Bydao=2*B(2,y-1)+B(2,y)+2*B(2,y+1);
geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
strength1(y)=sqrt(color(y))+geometry(y);
path(1,y)=y;
}//end
color=Mat_<float>::zeros(1,n);
geometry=Mat_<float>::zeros(1,n);
float small=0;
//开始扩展 向下一行 从第二行到倒数第二行 最后一行单独拿出来 像第一行一样 因为它的结构差值geometry不好算
//for i=2:H-1
for(int i=1;i<H-1;i++){
//先把下一行的强度值全部计算出来 到时候需要比较哪三个就拿出哪三个
//for j=L:R
for(int j=L;j<R;j++){
int x=i;
int y=j-L+1;
color(y)=A(i,j)-B(x,y);
if(y==1){
Axdao=2*A(i-1,j+1)+A(i,j+1)+2*A(i+1,j+1)-2*A(i-1,j-1)-A(i,j-1)-2*A(i+1,j-1);
Bxdao=2*B(x-1,y+1)+B(x,y+1)+2*B(x+1,y+1);
Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1)+2*A(i+1,j-1)+A(i+1,j)+2*A(i+1,j+1);
Bydao=-B(x-1,y)-2*B(x-1,y+1)+B(x+1,y)+2*B(x+1,y+1);
geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
strength2(y)=sqrt(color(y))+geometry(y);
continue;
}//end
if(j==R){
Axdao=-2*A(i-1,j-1)-A(i,j-1)-2*A(i+1,j-1);
Bxdao=2*B(x-1,y+1)+B(x,y+1)+2*B(x+1,y+1)-2*B(x-1,y-1)-B(x,y-1)-2*B(x+1,y-1);
Aydao=-2*A(i-1,j-1)-A(i-1,j)+2*A(i+1,j-1)+A(i+1,j);
Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1)+2*B(x+1,y-1)+B(x+1,y)+2*B(x+1,y+1);
geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
strength2(y)=sqrt(color(y))+geometry(y);
continue;
}//end
Axdao=2*A(i-1,j+1)+A(i,j+1)+2*A(i+1,j+1)-2*A(i-1,j-1)-A(i,j-1)-2*A(i+1,j-1);
Bxdao=2*B(x-1,y+1)+B(x,y+1)+2*B(x+1,y+1)-2*B(x-1,y-1)-B(x,y-1)-2*B(x+1,y-1);
Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1)+2*A(i+1,j-1)+A(i+1,j)+2*A(i+1,j+1);
Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1)+2*B(x+1,y-1)+B(x+1,y)+2*B(x+1,y+1);
geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
strength2(y)=sqrt(color(y))+geometry(y);
}//end
//for j=1:n
for(int j=0;j<n;j++){
if(path(i-1,j)==1){
if(strength2(1)<strength2(2)){
strength1(j)=strength1(j)+strength2(1);
path(i,j)=1;
}else{
strength1(j)=strength1(j)+strength2(2);
path(i,j)=2;
}//end
}else{
if(path(i-1,j)==n){
if(strength2(n-1)<strength2(n)){
strength1(j)=strength1(j)+strength2(n-1);
path(i,j)=n-1;
}else{
strength1(j)=strength1(j)+strength2(n);
path(i,j)=n;
}//end
}else{
if(strength2(path(i-1,j)-1)<strength2(path(i-1,j))){
if(strength2(path(i-1,j)-1)<strength2(path(i-1,j)+1)){
small=strength2(path(i-1,j)-1);
path(i,j)=path(i-1,j)-1;
}else{
small=strength2(path(i-1,j)+1);
path(i,j)=path(i-1,j)+1;
}//end
}else{
if(strength2(path(i-1,j))<strength2(path(i-1,j)+1)){
small=strength2(path(i-1,j));
path(i,j)=path(i-1,j);
}else{
small=strength2(path(i-1,j)+1);
path(i,j)=path(i-1,j)+1;
}//end
}//end
strength1(j)=strength1(j)+small;
}//end
}//end
small=0;
}//end
strength2=Mat_<float>::zeros(1,n);
color=Mat_<float>::zeros(1,n);
geometry=Mat_<float>::zeros(1,n);
//if (0==(i%10))cout<<i<<endl;//disp(i);end;
}//end
//cout<<"color:"<<color.rows<<"'"<<color.cols<<endl;
//单独计算最后一行
{
int i=H-1;
//for j=L:R
//cout<<"L,R:"<<L<<"'"<<R<<endl;
for(int j=L;j<R;j++){
int x=i;
int y=j-L+1;
//cout<<"i:"<<i<<endl;
//cout<<"j:"<<j<<endl;
//cout<<"x:"<<x<<endl;
//cout<<"y:"<<y<<endl;
color(y)=A(i,j)-B(x,y);
if(y==1){
Axdao=2*A(i-1,j+1)+A(i,j+1)-2*A(i-1,j-1)-A(i,j-1);
Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1);
Bxdao=2*B(x-1,y+1)+B(x,y+1);
Bydao=-B(x-1,y)-2*B(x-1,y+1);
continue;
}//end
if(j==R){
Bxdao=2*B(x-1,y+1)+B(x,y+1)-2*B(x-1,y-1)-B(x,y-1);
Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1);
Axdao=-2*A(i-1,j-1)-A(i,j-1);
Aydao=-2*A(i-1,j-1)-A(i-1,j);
continue;
}//end
Axdao=2*A(i-1,j+1)+A(i,j+1)-2*A(i-1,j-1)-A(i,j-1);
Bxdao=2*B(x-1,y+1)+B(x,y+1)-2*B(x-1,y-1)-B(x,y-1);
Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1);
Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1);
geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
strength2(y)=sqrt(color(y))+geometry(y);
}//end
//for j=1:n
for(int j=0;j<n;j++){
if(path(i-1,j)==1){
if(strength2(1)<strength2(2)){
strength1(j)=strength1(j)+strength2(1);
path(i,j)=1;
}else{
strength1(j)=strength1(j)+strength2(2);
path(i,j)=2;
}//end
}else{
if(path(i-1,j)==n){
if(strength2(n-1)<strength2(n)){
strength1(j)=strength1(j)+strength2(n-1);
path(i,j)=n-1;
}else{
strength1(j)=strength1(j)+strength2(n);
path(i,j)=n;
}//end
}else{
if(strength2(path(i-1,j)-1)<strength2(path(i-1,j))){
if(strength2(path(i-1,j)-1)<strength2(path(i-1,j)+1)){
small=strength2(path(i-1,j)-1);
path(i,j)=path(i-1,j)-1;
}else{
small=strength2(path(i-1,j)+1);
path(i,j)=path(i-1,j)+1;
}//end
}else{
if(strength2(path(i-1,j))<strength2(path(i-1,j)+1)){
small=strength2(path(i-1,j));
path(i,j)=path(i-1,j);
}else{
small=strength2(path(i-1,j)+1);
path(i,j)=path(i-1,j)+1;
}//end
}//end
strength1(j)=strength1(j)+small;
}//end
}//end
small=0;
}//end
}
//比较strength1里放的每条路径的强度值的总和 谁最小 就选path中对应的那一列的路径
//[minzhi,minth]=min(strength1);
float minzhi=strength1(0);
int minth=0;
for(int i=1;i<n;i++){
if(minzhi>strength1(i)){
minzhi=strength1(i);
minth=i;
}
}
Mat_<float> mypath=Mat_<float>::zeros(H,1);
//mypath=path(:,minth);
mypath=path.colRange(n-1,n);
//朋友MR_Radish666 说上句应该是:mypath=path.colRange(minth-1,minth);
//cout<<"一条最小路径:"<<endl<<mypath<<endl;
#undef A
#define A(x,y,i) A(x,y)[i-1]
#undef B
#define B(x,y,i) B(x,y)[i-1]
#define D(x,y,i) D(x,y)[i-1]
//mypath放的就是最佳缝合线选出的路径 这条路径坐标是参考图A 右边是目标图B
//for i=1:H
for(int i=0;i<H;i++){
for(int j=0;j<mypath(i)+L;j++){
D(i,j,1)=A(i,j,1);
D(i,j,2)=A(i,j,2);
D(i,j,3)=A(i,j,3);
}//end
for(int j=mypath(i)+L;j<Y;j++){
int x=i;
int y=j-L+1;
//if( y>W || x>H )continue;//end
D(i,j,1)=B(x,y,1);
D(i,j,2)=B(x,y,2);
D(i,j,3)=B(x,y,3);
}//end
}//end
//D=uint8(D);
// 画最佳缝合线
L=W+1+rdata1;
//figure;imshow(D)
//hold on;
for(int i=0;i<H;i++){
D(i,L+mypath(i),1)=1.0;
D(i,L+mypath(i),2)=1.0;
D(i,L+mypath(i),3)=1.0;
}//end
//hold off;
//Mat roi2;
//D.convertTo(roi2,CV_8U,255);
//imwrite("line.jpg",roi2);
return D;
#undef A
#undef B
#undef D
}
然后调用这个函数,调用前
先准备好,左、右图,(由于这个函数只能左向右拼,如果要向其它方向拼,可能要先翻转图像):
//左图
Mat_<Vec3f> l;
int x=p.x-(im.cols-w);
cout<<"x="<<x<<endl;
Mat l8u(dst, Rect(x, p.y, im.cols, im.rows));//左图
l8u2.convertTo(l,CV_32F,1.0/255.0);//Vec3f表示有三个通道,即 l[row][column][depth]
//imshow("l",l);
//右图
Mat_<Vec3f> r;
im.convertTo(r,CV_32F,1.0/255.0);
//缝合图
Mat_<Vec3f> bm=bestlinefusion(l,r,w);
//imshow("最佳缝合线",bm);
Mat src;
bm.convertTo(src,CV_8U,255);
Mat dstroi(dst, Rect(p.x, p.y, im.cols, im.rows));//大图中的右图位置
Rect r0(im.cols-w,0,im.cols,im.rows); // 只取右图位置
src(r0).convertTo(dstroi, dstroi.type(), 1,0); // 到大图
再把该文中的多分辨率拼接类保存为cpp放在我们的程序中
#include"v2.cpp"//多频段图像融合 类
和上面的函数类似,准备左、右、掩码图,调用
Mat_<Vec3f> blend = LaplacianBlend(l, r, m);//金字塔融合
blend.convertTo(dstroi,CV_8U,255);//到大图
效果图:
哪个重影已经没有了。
这个最佳缝合线好象不是很好,好多地方跑到重合区边界就成一条直线了,接缝就比较明显了
先这样吧。