一、基本原理及概念
圖像柱面投影算法作爲投影算法中的一種,能夠使圖片中的空間約束與視覺保持一致,在全景拼接的過程中,柱面投影算法有着非常重要的作用,是全景拼接預處理算法中不可或缺的步驟。
柱面投影的基本原理圖示如下,可以得到投影圖像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 (和本算法對比,解釋如何消除投影過程產生的黑色縫隙)