利用视差图合成新视点
利用视差图合成新视点,视差图一般通过图像匹配获取,以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.反向映射+空洞填充+双线性插值
上面生成虚拟视点位置的视差图时没有填充空洞,生成的虚拟视点会有很多裂纹存在。加上空洞填充能够有效消除裂纹。如下:
填充空洞后生的虚拟视点图如下,可见空洞裂纹得到有效消除:
---------------------------------
业精于勤而荒于嬉 行成于思而毁于随
---------------------------------