一、基本原理及概念
图像柱面投影算法作为投影算法中的一种,能够使图片中的空间约束与视觉保持一致,在全景拼接的过程中,柱面投影算法有着非常重要的作用,是全景拼接预处理算法中不可或缺的步骤。
柱面投影的基本原理图示如下,可以得到投影图像ABC平面到投影柱面DBE之间的像素空间变换关系,通过变换关系即可将平面上的像素压缩在柱面之上。
首先可以选择使用柱面图像坐标为空间计算输入,这样可以确保每一个柱面坐标都能够得到一个有效的平面坐标映射点,从而避免了从平面坐标系到柱面坐标系投影不存在的可能,完全避免了柱面图像缝隙的存在,根据右图可知,柱面坐标上与平面坐标中的关系如下:
而在方向上,由于人眼也是将光束聚焦到眼睛当中,因此在方向上需要满足如下变换关系式:
二、代码实现过程
1. MATLAB方式实现:
I = imread('C:/Users/Administrator/Desktop/mamiao/Test/images/doge.png'); [height, width, depth] = size(I); % A = zeros(size(I)); A = I; centerX = width / 2; centerY = height / 2; % alpha = pi / 4; f = width / (2 * tan(pi/4/2)); for i = 1 : width for j = 1 : height theta = asin((i - centerX) / f); pointX = int32(f * tan((i - centerX) / f) + centerX); pointY = int32((j - centerY) / cos(theta) + centerY); if pointX >= 1 && pointX <= width && pointY >= 1 && pointY <= height for k = 1:depth A(j,i,k) = I(pointY,pointX,k); end else for k = 1:depth A(j,i,k) = 0; end end end end %% % for i = 1 : width % for j = 1 : height % theta = asin((i - centerX) / f); % pointX = int32(f * theta + centerX); % int32(f * tan((i - centerX) / f) + centerX); % pointY = int32((j - centerY) * cos(theta) + centerY); % int32((j - centerY) / cos(theta) + centerY); % if pointX >= 1 && pointX <= width && pointY >= 1 && pointY <= height % for k = 1 : depth % A(pointY, pointX, k) = I(j, i, k); % end % end % end % end %% subplot(1, 2, 1); imshow(I); subplot(1, 2, 2); imshow(uint8(A));
2. C语言实现(请使用neg方式):
1 char barrel_func_neg(unsigned char const *Image,unsigned char *Res,unsigned int w, unsigned int h, unsigned int d, double vision_alpha) // 反向投影的方式确保数据不会出现断点 2 { 3 long row,clo,dep,line_size = w*d,sum = line_size*h; 4 int shadow_X,shadow_Y,center_X = w/2,center_Y = h/2; 5 double f,theta; 6 7 f = (double)center_X / tan(vision_alpha/2.0); // f = w / 2 / tan(theta/2) 8 for(clo=0;clo<w;clo++){ 9 for(row=0;row<h;row++){ 10 // theta = asin((double)(clo - center_X) / f); 11 theta = (double)(clo - center_X) / f; 12 shadow_X = (int)(f * tan((double)(clo - center_X) / f)+ center_X); 13 shadow_Y = (int)((double)(row - center_Y) / cos(theta) + center_Y); 14 if(shadow_X >= 0 && shadow_X < w && shadow_Y >= 0 && shadow_Y < h){ 15 for(dep=0;dep<d;dep++){ 16 *(Res + row*line_size + clo*d + dep) = *(Image + shadow_Y*line_size + shadow_X*d + dep); 17 } 18 }else{ 19 for(dep=0;dep<d;dep++){ 20 *(Res + row*line_size + clo*d + dep) = 0; 21 } 22 } 23 } 24 } 25 return 1; 26 } 27 28 char barrel_func_pos(unsigned char const *Image,unsigned char *Res,unsigned int w, unsigned int h, unsigned int d, double vision_alpha) 29 { 30 long row,clo,dep,line_size = w*d,sum = line_size*h; 31 int shadow_X,shadow_Y,center_X = w/2,center_Y = h/2; 32 double f,theta; 33 34 f = center_X / tan(vision_alpha/2); // f = w / 2 / tan(theta/2) 35 for(row=0;row<h;row++){ 36 for(clo=0;clo<w;clo++){ 37 theta = atan((double)(clo - center_X) / f); 38 shadow_X = (int)(f * theta + center_X); 39 shadow_Y = (int)((double)(row - center_Y) * cos(theta) + center_Y); 40 if(shadow_X >= 0 && shadow_X < w && shadow_Y >= 0 && shadow_Y < h){ 41 for(dep=0;dep<d;dep++){ 42 *(Res + shadow_Y*line_size + shadow_X*d + dep) = *(Image + row*line_size + clo*d + dep); 43 } 44 } 45 } 46 } 47 return 1; 48 }
采用neg方式函数逆向映射图像坐标点则不会出现图像缝隙的问题,具体分析问题的讨论参考这里;
上述算法运行结果如下所示:
请忽略红色角点检测结果...
Reference
【Octave】柱面投影简析:https://www.cnblogs.com/cheermyang/p/5431170.html
图像の柱面投影算法:https://blog.csdn.net/weixinhum/article/details/50611750
图像柱面投影:https://blog.csdn.net/Young__Fan/article/details/82952854 (和本算法对比,解释如何消除投影过程产生的黑色缝隙)