专栏首页一棹烟波利用视差图合成新视点

利用视差图合成新视点

利用视差图合成新视点,视差图一般通过图像匹配获取,以middlebury上的一张图为例,左边为原图(左图像),右边为对应视差图(灰度图)。

1. 正向映射:

简单的利用左视点原图和视差图进行视点合成,取每一个像素点处的视差值,然后计算新图像中像素点位置,然后赋值。前向映射,单点赋值代码如下。配置完Opencv可以直接跑,如下图:

 1 #include <iostream>
 2 #include <string>
 3 #include <opencv.hpp>
 4 
 5 using namespace std;
 6 using namespace cv;
 7 
 8 void main()
 9 {
10     string imgPath="data/source_images/teddy/";
11     Mat srcImgL=imread(imgPath+"imgL.png");
12     Mat dispL=imread(imgPath+"dispL.png",0);
13     dispL=dispL/4;
14 
15     int imgHeight=srcImgL.rows;
16     int imgWidth=srcImgL.cols;
17     int channels=srcImgL.channels();
18 
19     Mat dstImgL=Mat::zeros(imgHeight,imgWidth, CV_8UC3);
20 
21     uchar* pImgDataL=(uchar*)srcImgL.data;
22     uchar* pDispDataL=(uchar*)dispL.data;
23     uchar* pDstDataL=(uchar*)dstImgL.data;
24 
25     VideoWriter writer("video.avi", CV_FOURCC('D','I','V','X'), 30, Size(imgWidth, imgHeight), 1);
26     int cnt=0;
27     int viewCnt=50;
28     while (cnt !=4)
29     {
30         for (int k=0; k<viewCnt; k++)
31         {
32             dstImgL.setTo(0);
33             float interp;
34             if (cnt%2==0)    interp=(float)k/viewCnt;
35             else  interp=float(viewCnt-k)/viewCnt;
36             for (int j=0; j<imgHeight; j++)
37             {
38                 for (int i=0; i<imgWidth; i++)
39                 {
40                     uchar dispL=pDispDataL[j*imgWidth+i];
41                     float offsetL=dispL* interp;
42                     int idL=(int)(offsetL+0.5);  //计算视差值
43 
44                     if (idL+i>=imgWidth) continue;
45                     //插值结果
46                     int idxResult=(j*imgWidth+i)*channels;
47                     int idx=(j*imgWidth+i+idL)*channels;
48                     for (int chan=0; chan<channels; chan++)
49                     {
50                          pDstDataL[idxResult+chan]=pImgDataL[idx+chan];
51                     }
52                 }
53             }
54             namedWindow("show");
55             imshow("show", dstImgL);
56             waitKey(10); 
57             writer<<dstImgL;
58         }
59         cnt++;
60     }
61     writer.release();
62 }

边缘有锯齿,随后找时间加上反向映射以及双线性插值的版本。

2. 反向映射

先根据左视点视差图生成虚拟视点的视差图,然后反向映射得到每一个像素点在原图像中的浮点位置,利用线性插值获取最终颜色值。(虚拟视点位置视差图没有填充空洞版本),可见有很多裂纹。

  1 #include <iostream>
  2 #include <string>
  3 #include <opencv.hpp>
  4 
  5 using namespace std;
  6 using namespace cv;
  7 
  8 int index(int m, int n)
  9 {
 10     if (m>=0 && m<n)
 11         return m;
 12     else if (m<0)
 13         return 0;
 14     else if (m>=n)
 15         return n-1;
 16 }
 17 
 18 void obtainNewDispMap(const Mat &refDisp, Mat &dstDisp, float value)
 19 {
 20     int height=refDisp.rows;
 21     int width=refDisp.cols;
 22     uchar* pSrcDispData=(uchar*) refDisp.data;
 23     float* pDstDispData=(float*) dstDisp.data;
 24     for (int j=0; j<height; j++)
 25     {
 26         for (int i=0; i<width; i++)
 27         {
 28             int disp=(int)pSrcDispData[j*width+i];
 29             float newDisp=disp*(value);
 30             int inew=(int)(i-newDisp);
 31             inew=index(inew, width);
 32             pDstDispData[j*width+inew]=newDisp;
 33         } 
 34     }
 35 }
 36 
 37 void main(void)
 38 {
 39     string imgPath="data/source_images/teddy/";
 40     Mat srcImgL=imread(imgPath+"imgL.png");
 41     Mat dispL=imread(imgPath+"dispL.png",0);
 42     dispL=dispL/4;
 43 
 44     int imgHeight=srcImgL.rows;
 45     int imgWidth=srcImgL.cols;
 46 
 47     Mat dstImgL=Mat::zeros(imgHeight,imgWidth, CV_8UC3);
 48     Mat dstImg=Mat::zeros(imgHeight,imgWidth, CV_8UC3);
 49     Mat dstNewDispImg=Mat::zeros(imgHeight,imgWidth, CV_32FC1);
 50 
 51     uchar* pImgDataL=(uchar*)srcImgL.data;
 52     uchar* pDispDataL=(uchar*)dispL.data;
 53     uchar* pDstDataL=(uchar*)dstImgL.data;
 54 
 55     VideoWriter writer("video.avi", CV_FOURCC('D','I','V','X'), 30, Size(imgWidth, imgHeight), 1); 
 56     int cnt=0;
 57     int viewCnt=50;
 58     while (cnt!=4)
 59     {
 60         float interp;
 61         for (int k=0; k<viewCnt; k++)
 62         {
 63             dstNewDispImg.setTo(255);
 64             dstImgL.setTo(0);
 65             if (cnt%2==0)   interp=(float)k/viewCnt;
 66             else interp=(float)(viewCnt-k)/viewCnt;
 67 
 68             obtainNewDispMap(dispL, dstNewDispImg, interp);
 69 
 70             float* pNewDispData=(float*)dstNewDispImg.data;
 71             for (int j=0; j<imgHeight; j++)
 72             {
 73                 for (int i=0; i<imgWidth; i++)
 74                 {
 75                     float disp=pNewDispData[j*imgWidth+i];
 76                     float id=i+disp;
 77 
 78                     int id0=floor(id);
 79                     int id1=floor(id+1);
 80                 
 81                     float weight1=1-(id-id0);
 82                     float weight2=id-id0;
 83 
 84                     id0=index(id0, imgWidth);
 85                     id1=index(id1, imgWidth);
 86 
 87                     //插值结果
 88                     pDstDataL[j*imgWidth*3+i*3+0]=weight1*pImgDataL[j*imgWidth*3+id0*3+0]+weight2*pImgDataL[j*imgWidth*3+id1*3+0];
 89                     pDstDataL[j*imgWidth*3+i*3+1]=weight1*pImgDataL[j*imgWidth*3+id0*3+1]+weight2*pImgDataL[j*imgWidth*3+id1*3+1];
 90                     pDstDataL[j*imgWidth*3+i*3+2]=weight1*pImgDataL[j*imgWidth*3+id0*3+2]+weight2*pImgDataL[j*imgWidth*3+id1*3+2];
 91                 }
 92             }
 93             namedWindow("virImg");
 94             imshow("virImg", dstImgL);
 95             waitKey(10);
 96             writer<<dstImgL;
 97         }
 98         cnt++;
 99     }
100    writer.release();
101 }

 3.反向映射+空洞填充+双线性插值

上面生成虚拟视点位置的视差图时没有填充空洞,生成的虚拟视点会有很多裂纹存在。加上空洞填充能够有效消除裂纹。如下:

填充空洞后生的虚拟视点图如下,可见空洞裂纹得到有效消除:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • OpenCV3.4两种立体匹配算法效果对比

     以OpenCV自带的Aloe图像对为例: ? ? ? 1.BM算法(Block Matching) 参数设置如下: int numberOfDispa...

    一棹烟波
  • 直方图实现快速中值滤波

    中值滤波能够有效去除图像中的异常点,具有去除图像噪声的作用。传统中值滤波的算法一般都是在图像中建立窗口,然后对窗口内的所有像素值进行排序,选择排序后的中间值作为...

    一棹烟波
  • two Pass方法连通域检测

    原理: Two-Pass方法检测连通域的原理可参见这篇博客:http://blog.csdn.net/lichengyu/article/details/139...

    一棹烟波
  • 简单的验证码识别(opecv)

           opencv版本: 3.0.0            处理验证码: 纯数字验证码 (颜色不同,有噪音,和带有较多的划痕)             ...

    Gxjun
  • 2017.10.2解题报告

    预计分数:60+0+30=90 实际分数:60+0+0=60 T1:https://www.luogu.org/problem/show?pid=T...

    attack
  • 1025 反转链表 (25 分)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    韩旭051
  • ACM札记之一

    输入n(n<=100)个整数,按照绝对值从大到小排序后输出。题目保证对于每一个测试实例,所有的数的绝对值都不相等。

    慕白
  • 不相交集类应用:迷宫生成

    1 #include <iostream> 2 #include <vector> 3 #include <cstdlib> 4 #includ...

    用户1154259
  • 欧拉计划 problem 16

    题目 幂的数字和 215 = 32768,而32768的各位数字之和是 3 + 2 + 7 + 6 + 8 = 26。

    用户4492257
  • 51nod 1649 齐头并进(Codeforces 601A The Two Routes) (最短路)

    题目链接(Codeforces):http://codeforces.com/problemset/problem/601/A

    Ch_Zaqdt

扫码关注云+社区

领取腾讯云代金券