利用视差图合成新视点,视差图一般通过图像匹配获取,以middlebury上的一张图为例,左边为原图(左图像),右边为对应视差图(灰度图)。
简单的利用左视点原图和视差图进行视点合成,取每一个像素点处的视差值,然后计算新图像中像素点位置,然后赋值。前向映射,单点赋值代码如下。配置完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 }
边缘有锯齿,随后找时间加上反向映射以及双线性插值的版本。
先根据左视点视差图生成虚拟视点的视差图,然后反向映射得到每一个像素点在原图像中的浮点位置,利用线性插值获取最终颜色值。(虚拟视点位置视差图没有填充空洞版本),可见有很多裂纹。
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 }
上面生成虚拟视点位置的视差图时没有填充空洞,生成的虚拟视点会有很多裂纹存在。加上空洞填充能够有效消除裂纹。如下:
填充空洞后生的虚拟视点图如下,可见空洞裂纹得到有效消除: