鱼眼图像到柱面的反投影及柱面到鱼眼图像的投影
https://blog.csdn.net/c20081052/article/details/80999904
鱼眼图像到柱面图像的投影公式推导参考链接,自己照着推导过,应该是没有问题的。这个是平面图像到柱面的投影,我理解的鱼眼图像也是平面图像,所以也是用的同样的公式,就不推导了,直接上代码。
编译环境是vc6.0+opencv1.0
鱼眼图像到柱面投影:
int Plane2Cylinder(const IplImage* srcImage,IplImage* dstImage, double f)
{int height = srcImage->height; //原图像的高(即原图像矩阵行数)int width = srcImage->width; //原图像的宽(即原图像矩阵列数)int centerX = width / 2; //图像中心横坐标int centerY = height / 2; //图像中心纵坐标double alpha = CV_PI / 4; //相机视角角度// f = width / (2 * tan(alpha / 2)); //焦距(圆的半径)unsigned char f1, f2, f3, f4;unsigned char bVal,gVal,rVal;float x,y;//对应柱面图像上的坐标int pointX,pointY;//整数部分int ix,iy;//小数部分//循环遍历for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){//注意图像坐标与像素矩阵坐标的区别float theta = atan((j - centerX) / f);// x = f * alpha / 2 + f * theta; //用f * alpha / 2,两边缝隙会不均匀(只有右边有黑缝隙),用width / 2就均匀了x = width / 2 + f * theta; //用f * alpha / 2,两边缝隙会不均匀(只有右边有黑缝隙),用width / 2就均匀了y = f * (i - centerY) / sqrt((j - centerX) * (j - centerX) + f * f) + centerY;pointX = (int)x;pointY = (int)y;#if 1if (pointX >=0 && pointY >= 0 && pointX < width && pointY < height)//越界判断{// 获取原图像素值bVal = ((uchar *)(srcImage->imageData + i*srcImage->widthStep))[j*srcImage->nChannels ];// copy到融合图(dstImage->imageData + pointY*dstImage->widthStep)[pointX*dstImage->nChannels ] = bVal ; // B }
#endif}}return 0;}
柱面投影到平面上代码:
#if 1
int Cylinder2Plane(const IplImage* srcImage,IplImage* dstImage, double f)
{int height = srcImage->height; //鱼眼图像的高(即原图像矩阵行数)int width = srcImage->width; //鱼眼原图像的宽(即原图像矩阵列数)int centerX = width / 2; //图像中心横坐标int centerY = height / 2; //图像中心纵坐标double alpha = CV_PI / 4; //相机视角角度// f = width / (2 * tan(alpha / 2)); //焦距(圆的半径)unsigned char bVal,bVals,bValp;float i,j;float is,js;//垂直float ip,jp;//平行int pointi,pointj;//整数部分int pointis,pointjs;//整数部分int pointip,pointjp;//整数部分unsigned char sumVal;//循环遍历for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){j = f * tan((x - centerX) / f ) + centerX; //i = (y - centerY) * sqrt(tan((y - centerX) / f) * tan((y - centerX )/ f) +1) + centerY;//// jp = f * tan((x+1 - centerX) / f ) + centerX; //// ip = (y - centerY) * sqrt(tan((y - centerX) / f) * tan((y - centerX )/ f) +1) + centerY;//// js = f * tan((x - centerX) / f ) + centerX; //// is = (y+1 - centerY) * sqrt(tan((y+1 - centerX) / f) * tan((y+1 - centerX )/ f) +1) + centerY;//pointi = (int)i;pointj = (int)j;// pointip = (int)ip;// pointjp = (int)jp;// pointis = (int)is;// pointjs = (int)js;// 获取原图像素值if (pointj >=0 && pointi >= 0 && pointj < width && pointi < height /*&&pointjs >=0 && pointis >= 0 && pointjs < width && pointis < height &&pointjp >=0 && pointip >= 0 && pointjp < width && pointip < height */ )
#if 1{bVal = ((uchar *)(srcImage->imageData + y*srcImage->widthStep))[x*srcImage->nChannels];// bVals = ((uchar *)(srcImage->imageData + (y+1)*srcImage->widthStep))[x*srcImage->nChannels];// bValp = ((uchar *)(srcImage->imageData + y*srcImage->widthStep))[(x+1)*srcImage->nChannels ];// copy到融合图(dstImage->imageData + pointi*dstImage->widthStep)[pointj*dstImage->nChannels] = bVal ; // B // (dstImage->imageData + pointi*dstImage->widthStep)[pointj*dstImage->nChannels] = bVal +sqrt((bVal - bVals)*(bVal - bVals) +(bVal - bValp) *(bVal - bValp) ) ;// (dstImage->imageData + pointis*dstImage->widthStep)[pointjs*dstImage->nChannels] = bVals+sqrt((bVal - bVals)*(bVal - bVals) +(bVal - bValp) *(bVal - bValp) ) ;// (dstImage->imageData + pointip*dstImage->widthStep)[pointjp*dstImage->nChannels] = bValp +sqrt((bVal - bVals)*(bVal - bVals) +(bVal - bValp) *(bVal - bValp) ) ;}
#endif}}return 0;}
#endif
代码里面实现的是最邻近插值和单通道图像的处理,柱面到平面的投影只是将平面到柱面的投影公式反推回去,屏蔽的代码是实现的三通道的效果。
先上效果图:
图片2效果可以看出采用最邻近插值会有部分信息丢失,边缘有锯齿感,图3再将柱面图像投影到平面上,效果上看公式逆推应该没有问题,但是出现很多黑色网格线,我感觉是从平面往柱面上投影的之后,在柱面图像上取整,然后再投影回平面时这一过程导致部分信息丢失,只是怀疑,没时间验证,如果有高手能解决问题,可以交流一下。
至于为什么要这样投影来投影去呢?
主要是鱼眼图像畸变严重,且是非线性存储,对其直接处理很麻烦,所以投影到线性存储的柱面进行处理。
本文只是为了记录研究的过程,有空如有改进会持续更新。