panolib.c: Implemented bilinear interpolation.
[libopano.git] / src / panolib.c
1 /* Panorama_Tools       -       Generate, Edit and Convert Panoramic Images
2    Copyright (C) 1998,1999 - Helmut Dersch  der@fh-furtwangen.de
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 /*------------------------------------------------------------*/
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <assert.h>
22
23 #include "filter.h"
24 #include "panolib.h"
25 #include "utils_math.h"
26 #include "utils_image.h"
27
28 #define DEG_TO_RAD(x) ((x) * 2.0 * M_PI / 360.0 )
29
30 // Lookup Tables for Trig-functions and interpolator
31
32 #define NATAN 2048
33 #define NSQRT 2048
34
35 static void matrix_matrix_mult( double m1[3][3],double m2[3][3],double result[3][3])
36 {
37         int i,k;
38         
39         for(i=0;i<3;i++)
40                 for(k=0; k<3; k++)
41                         result[i][k] = m1[i][0] * m2[0][k] + m1[i][1] * m2[1][k] + m1[i][2] * m2[2][k];
42 } /* void matrix_matrix_mult */
43
44 /* Set matrix elements based on Euler angles a, b, c */
45 static void set_transformation_matrix (double m[3][3],
46                 double a, double b, double c)
47 {
48         double mx[3][3], my[3][3], mz[3][3], dummy[3][3];
49         
50
51         // Calculate Matrices;
52
53         mx[0][0] = 1.0 ;                                mx[0][1] = 0.0 ;                                mx[0][2] = 0.0;
54         mx[1][0] = 0.0 ;                                mx[1][1] = cos(a) ;                     mx[1][2] = sin(a);
55         mx[2][0] = 0.0 ;                                mx[2][1] =-mx[1][2] ;                   mx[2][2] = mx[1][1];
56         
57         my[0][0] = cos(b);                              my[0][1] = 0.0 ;                                my[0][2] =-sin(b);
58         my[1][0] = 0.0 ;                                my[1][1] = 1.0 ;                                my[1][2] = 0.0;
59         my[2][0] = -my[0][2];                   my[2][1] = 0.0 ;                                my[2][2] = my[0][0];
60         
61         mz[0][0] = cos(c) ;                     mz[0][1] = sin(c) ;                     mz[0][2] = 0.0;
62         mz[1][0] =-mz[0][1] ;                   mz[1][1] = mz[0][0] ;                   mz[1][2] = 0.0;
63         mz[2][0] = 0.0 ;                                mz[2][1] = 0.0 ;                                mz[2][2] = 1.0;
64
65         /* Calculate `m = mz * mx * my' */
66
67         matrix_matrix_mult( mz, mx,     dummy);
68         matrix_matrix_mult( dummy, my, m);
69 } /* void SetMatrix */
70
71 static int copy_pixel (ui_image_t *dest, const ui_image_t *src,
72                 int x_dest, int y_dest,
73                 double x_src_fp, double y_src_fp,
74                 interpolator_t interp)
75 {
76         uint32_t pixel_dest = (y_dest * dest->width) + x_dest;
77
78         assert (x_src_fp >= 0.0);
79         assert (y_src_fp >= 0.0);
80
81         if (interp == BILINEAR)
82         {
83                 int x_src_left;
84                 int x_src_right;
85                 int y_src_top;
86                 int y_src_bottom;
87
88                 double x_right_frac;
89                 double y_bottom_frac;
90
91                 int i;
92
93                 x_src_left = (int) x_src_fp;
94                 x_src_right = x_src_left + 1;
95                 y_src_top  = (int) y_src_fp;
96                 y_src_bottom = y_src_top + 1;
97
98                 x_right_frac = x_src_fp - x_src_left;
99                 y_bottom_frac = y_src_fp - y_src_top;
100
101                 assert (x_src_right < src->width);
102                 assert (y_src_bottom < src->height);
103
104                 assert ((x_right_frac >= 0.0) && (x_right_frac <= 1.0));
105                 assert ((y_bottom_frac >= 0.0) && (y_bottom_frac <= 1.0));
106
107                 for (i = 0; i < 3; i++)
108                 {
109                         uint8_t values[2][2];
110                         double value_left;
111                         double value_right;
112                         double value_final;
113
114                         values[0][0] = src->data[i][(y_src_top * src->width) + x_src_left];
115                         values[0][1] = src->data[i][(y_src_top * src->width) + x_src_right];
116                         values[1][0] = src->data[i][(y_src_bottom * src->width) + x_src_left];
117                         values[1][1] = src->data[i][(y_src_bottom * src->width) + x_src_right];
118
119                         value_left = (1.0 - y_bottom_frac) * values[0][0]
120                                 + y_bottom_frac * values[1][0];
121                         value_right = (1.0 - y_bottom_frac) * values[0][1]
122                                 + y_bottom_frac * values[1][1];
123
124                         value_final = (1.0 - x_right_frac) * value_left + x_right_frac * value_right;
125
126                         assert ((value_final >= 0.0) && (value_final <= 255.0));
127
128                         dest->data[i][pixel_dest] = (uint8_t) (value_final + 0.5);
129                 }
130         }
131         else /* if (interp == NNEIGHBOUR) */
132         {
133                 int x_src = (int) (x_src_fp + 0.5) % src->width;
134                 int y_src = (int) (y_src_fp + 0.5) % src->height;
135
136                 if ((x_src < 0) || (x_src >= src->width)
137                                 || (y_src < 0) || (y_src >= src->height))
138                 {
139                         dest->data[0][pixel_dest] = 0;
140                         dest->data[1][pixel_dest] = 0;
141                         dest->data[2][pixel_dest] = 0;
142                 }
143                 else
144                 {
145                         uint32_t pixel_src = (y_src * src->width) + x_src;
146
147                         dest->data[0][pixel_dest] = src->data[0][pixel_src];
148                         dest->data[1][pixel_dest] = src->data[1][pixel_src];
149                         dest->data[2][pixel_dest] = src->data[2][pixel_src];
150                 }
151         }
152
153         return (0);
154 } /* int copy_pixel */
155
156 //    Main transformation function. Destination image is calculated using transformation
157 //    Function "func". Either all colors (color = 0) or one of rgb (color =1,2,3) are
158 //    determined. If successful, TrPtr->success = 1. Memory for destination image
159 //    must have been allocated and locked!
160
161 int pl_extract_view (ui_image_t *view, const ui_image_t *pano,
162                 double pitch, double yaw, double fov, interpolator_t interp)
163 {
164         int x_dest, y_dest; // Loop through destination image
165
166         int dest_width_left = view->width  / 2 ;  
167         int dest_height_top = view->height / 2 ;
168         int src_width_left =  pano->width   / 2 ;
169         int src_height_top =  pano->height  / 2 ;
170         
171         double v[3];
172         int     x_min, x_max, y_min, y_max;
173
174         /* The transformation matrix */
175         double tm[3][3];
176
177         double dist_r;
178         double dist_e;
179
180         { /* What the fuck does this? -octo */
181                 double a = DEG_TO_RAD (fov);
182                 double b = 2.0 * M_PI; /* DEG_TO_RAD (360.0) */
183
184                 dist_r = ((double) view->width) / (2.0 * tan (a / 2.0));
185                 dist_e = ((double) pano->width) / b;
186         }
187
188         set_transformation_matrix (tm, DEG_TO_RAD (pitch), DEG_TO_RAD (yaw), 0.0);
189
190         x_min = -dest_width_left; x_max = view->width - dest_width_left;
191         y_min = -dest_height_top; y_max = view->height - dest_height_top;
192
193         for(y_dest = y_min; y_dest < y_max; y_dest++)
194         {
195                 for(x_dest = x_min; x_dest < x_max; x_dest++)
196                 {
197                         double x_src_fp;
198                         double y_src_fp;
199
200                         v[0] = tm[0][0] * x_dest + tm[1][0] * y_dest + tm[2][0] * dist_r;
201                         v[1] = tm[0][1] * x_dest + tm[1][1] * y_dest + tm[2][1] * dist_r;
202                         v[2] = tm[0][2] * x_dest + tm[1][2] * y_dest + tm[2][2] * dist_r;
203
204                         x_src_fp = dist_e * atan2 (v[0], v[2]);
205                         y_src_fp = dist_e * atan2 (v[1], sqrt (v[2] * v[2] + v[0] * v[0]));
206
207                         copy_pixel (view, pano,
208                                         dest_width_left + x_dest, dest_height_top + y_dest,
209                                         src_width_left + x_src_fp, src_height_top + y_src_fp,
210                                         interp); /* FIXME */
211                 }
212         }
213         
214         return (0);
215 }
216
217 /*
218  * vim: set tabstop=4 softtabstop=4 shiftwidth=4 :
219  */