RemapFilter: projection.c

File projection.c, 10.6 KB (added by Floris Sluiter, 10 years ago)

Example to generate pgm files for front projection

Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <libgen.h>
4#include <string.h>
5#include <getopt.h>
6#include <math.h>
7
8
9
10/* Compile with: gcc projection.c -Wall -o project -lm
11 * math.h does not like to be linked directly...
12 */
13
14/* Flag set by ‘--verbose’. */
15static int verbose_flag;
16
17typedef struct double2{
18 double x;
19 double y;
20}double2;
21typedef struct double3{
22 double x;
23 double y;
24 double z;
25}double3;
26
27
28enum CameraMode {
29 FRONT,
30 FRONT235,
31 BACK,
32 UP,
33 DOWN,
34 SAMSUNG_GEAR_360,
35 THETAS
36};
37
38typedef struct configuration {
39 char* xmap_filename;
40 char* ymap_filename;
41 int xmap_set;
42 int ymap_set;
43 int rows; // target
44 int cols; // target
45 int height; //source
46 int width;//source
47 int rows_set;
48 int cols_set;
49 int height_set;
50 int width_set;
51 int crop;
52 enum CameraMode mode;
53} configuration;
54
55configuration parse_options(int argc, char **argv){
56 int c;
57 configuration po; //to hold parsed options
58 po.xmap_filename=NULL;
59 po.ymap_filename=NULL;
60 po.xmap_set=0;
61 po.ymap_set=0;
62 po.rows=0;
63 po.cols=0;
64 po.rows_set=0;
65 po.cols_set=0;
66 po.height_set=0;
67 po.width_set=0;
68 po.mode=FRONT; //default
69
70 while (1)
71 {
72 static struct option long_options[] =
73 {
74 /* These options set a flag. */
75 {"verbose", no_argument, &verbose_flag, 1},
76 {"brief", no_argument, &verbose_flag, 0},
77
78 /* These options don’t set a flag.
79 We distinguish them by their indices. */
80 {"help", no_argument, 0, 'q'},
81
82 /* options with arg*/
83 {"xmap", required_argument, 0, 'x'},
84 {"ymap", required_argument, 0, 'y'},
85 {"rows", required_argument, 0, 'r'},//target
86 {"cols", required_argument, 0, 'c'},//target
87 {"height", required_argument, 0, 'h'},//source
88 {"width", required_argument, 0, 'w'},//source
89 {"mode", required_argument, 0, 'm'},
90 {"crop", required_argument, 0, 'b'},
91
92 {0, 0, 0, 0}
93 };
94 /* getopt_long stores the option index here. */
95 int option_index = 0;
96
97 c = getopt_long (argc, argv, "qx:y:r:c:h:w:m:b:",
98 long_options, &option_index);
99
100 /* Detect the end of the options. */
101 if (c == -1)
102 break;
103
104 switch (c)
105 {
106 case 0:
107 /* If this option set a flag, do nothing else now. */
108 if (long_options[option_index].flag != 0)
109 break;
110 printf ("option %s", long_options[option_index].name);
111 if (optarg)
112 printf (" with arg %s", optarg);
113 printf ("\n");
114 break;
115
116 case 'x':
117 po.xmap_filename = optarg;
118 po.xmap_set++;
119 break;
120
121 case 'y':
122 po.ymap_filename = optarg;
123 po.ymap_set++;
124 break;
125 case 'h':
126 po.height = atoi(optarg);
127 po.height_set++;
128 break;
129 case 'w':
130 po.width = atoi(optarg);
131 po.width_set++;
132 break;
133 case 'c':
134 po.cols = atoi(optarg);
135 po.cols_set++;
136 break;
137 case 'r':
138 po.rows = atoi(optarg);
139 po.rows_set++;
140 break;
141 case 'b':
142 po.crop = atoi(optarg);
143 break;
144 case 'm':
145 if (strcmp(optarg, "front") == 0)
146 {
147 po.mode = FRONT;
148 }
149 else if (strcmp(optarg, "front235") == 0)
150 {
151 po.mode = FRONT235;
152 }
153 else if (strcmp(optarg, "down") == 0)
154 {
155 po.mode = DOWN;
156 }
157 else if (strcmp(optarg, "samsung_gear_360") == 0)
158 {
159 po.mode = SAMSUNG_GEAR_360;
160 }
161 else if (strcmp(optarg, "thetas") == 0)
162 {
163 po.mode = THETAS;
164 }
165 /* more else if clauses */
166 else /* default: */
167 {
168 printf("Camera mode %s not implemented \n",optarg); exit(1);
169 }
170 break;
171
172 case '?':
173 /* getopt_long already printed an error message. */
174 case 'q':
175 printf ("Usage: %s -x|--xmap FILE_x.pgm -y|--ymap FILE_y.pgm -h|--height 300 -w|--width 400 -r|--rows 600 -c|--cols 800 \n", argv[0]);
176 printf ("h,w is source size, r,c is targetsize \n");
177 exit(1);
178 break;
179
180 default:
181 abort ();
182 }
183 }
184
185 /* Instead of reporting ‘--verbose’
186 and ‘--brief’ as they are encountered,
187 we report the final status resulting from them. */
188 if(verbose_flag){
189 switch(po.mode){
190 case FRONT: printf("Camera: Front proj\n"); break;
191 case FRONT235: printf("Camera: Front 235 proj\n"); break;
192 case DOWN: printf("Camera: Down proj\n"); break;
193 case SAMSUNG_GEAR_360: printf("Camera: samsung_gear_360\n"); break;
194 case THETAS: printf("Camera: Theta S\n"); break;
195 default: printf("Camera mode not in verbose, exiting\n"); exit(1);
196 }
197 }
198 /* Print any remaining command line arguments (not options). */
199 if (optind < argc)
200 {
201 printf ("ERROR: non-option ARGV-elements: ");
202 while (optind < argc)
203 printf ("%s ", argv[optind++]);
204 putchar ('\n');
205 exit(1);
206 }
207
208 if(po.xmap_set!=1||po.ymap_set!=1){ printf("ERROR: Xmap and ymap are mandatory arguments and have to appear only once!\ntry --help for help\n\n ");exit(-1);}
209 if(po.rows_set!=1||po.cols_set!=1){ printf("ERROR: Target Rows and Cols are mandatory arguments and have to appear only once!\ntry --help for help\n\n ");exit(-1);}
210 if(po.height_set!=1||po.width_set!=1){ printf("ERROR: Source Height and Width are mandatory arguments and have to appear only once!\ntry --help for help\n\n ");exit(-1);}
211 return po;
212}
213
214#define MAXROWS 4500
215#define MAXCOLS 4500
216
217int pgmWrite_ASCII(char* filename, int rows,int cols,
218 int **image,char* comment_string) {
219 FILE* file; /* pointer to the file buffer */
220// int maxval; /* maximum value in the image array */
221 long nwritten = 0; /* counter for the number of pixels written */
222 long x,y; /* for loop counters */
223
224 /* return 0 if the dimensions are larger than the image array. */
225 if (rows > MAXROWS || cols > MAXCOLS) {
226 printf ("ERROR: row/col specifications larger than image array:\n");
227 return (0);
228 }
229
230 /* open the file; write header and comments specified by the user. */
231 if ((file = fopen(filename, "w")) == NULL) {
232 printf("ERROR: file open failed\n");
233 return(0);
234 }
235 fprintf(file,"P2\n");
236
237 if (comment_string != NULL) fprintf(file,"# %s \n", comment_string);
238
239 /* write the dimensions of the image */
240 fprintf(file,"%i %i \n", cols, rows);
241
242 /* NOTE: MAXIMUM VALUE IS WHITE; COLOURS ARE SCALED FROM 0 - */
243 /* MAXVALUE IN A .PGM FILE. */
244
245 /* WRITE MAXIMUM VALUE TO FILE */
246 fprintf(file, "%d\n", (int)65535);
247
248 /* Write data */
249
250 for (y = 0; y<rows;y++){
251 for (x = 0; x < cols; x++){
252 fprintf(file,"%i ",image[y][x]);
253 nwritten++;
254 }
255 fprintf(file,"\n");
256 }
257 fprintf(file,"\n");
258
259
260 printf ("\nNumber of pixels total(from rows*cols): %i\n",rows*cols);
261 printf ("Number of pixels written in file %s: %ld\n\n",filename,nwritten);
262
263 fclose(file);
264 return(1);
265}
266
267
268
269
270/* So, to get the x’,y’ position for the circular image we will have to first pass the
271 * coordinates x,y from the rectangular output image to spherical coordinates using the
272 * first coordinate system, then those to the second shown spherical coordinate system,
273 * then those to the polar projection and then pass the polar system to cardinal x’,y’.
274 */
275double2 evaluatePixel_Front(double2 outCoord, double2 srcSize)
276{
277 double2 o;
278 double theta,phi;
279 double3 sphericCoords;
280 double phi2_over_pi;
281 double theta2;
282 double2 inCentered;
283
284//convert outcoords to radians (180 = pi, so half a sphere)
285 o.x = outCoord.x / srcSize.x;
286 o.y = outCoord.y / srcSize.y;
287 theta = (1.0-o.x) * M_PI;
288 phi = o.y * M_PI;
289
290//Convert outcoords to spherical (x,y,z on unisphere)
291 sphericCoords.x = cos(theta)*sin(phi);
292 sphericCoords.y = sin(theta)*sin(phi);
293 sphericCoords.z = cos(phi);
294
295//Convert spherical to input coordinates...
296 theta2 = atan2(-sphericCoords.z,sphericCoords.x);
297 phi2_over_pi = acos(sphericCoords.y)/(M_PI);
298
299 inCentered.x = ((phi2_over_pi*cos(theta2))+0.5)*srcSize.x;
300 inCentered.y = ((phi2_over_pi*sin(theta2))+0.5)*srcSize.y;
301
302 return inCentered;
303}
304
305
306void gen_front_maps(configuration cfg,int** image_x,int** image_y ){
307 int x,y;
308
309 printf("Front proj\n");
310 for (y = 0; y<cfg.rows;y++){
311 for (x = 0; x < cfg.cols; x++){
312 double2 o = evaluatePixel_Front((double2){((double)x/((double)cfg.cols)) * ((cfg.width)-(2*cfg.crop)),
313 ((double)y/(double)cfg.rows) * ((cfg.height) -(2*cfg.crop))},
314 (double2){(cfg.width)-(2*cfg.crop), cfg.height-(2*cfg.crop)});
315 image_x[y][x] = (int)round(o.x)+cfg.crop;
316 image_y[y][x] = (int)round(o.y)+cfg.crop;
317 }
318 }
319}
320
321
322int
323main (int argc, char **argv)
324{
325 int y;
326 int** image_x;
327 int** image_y;
328 configuration cfg = parse_options(argc,argv);
329
330
331 if(cfg.xmap_filename) printf("xmapfile: %s\n",cfg.xmap_filename);
332 if(cfg.ymap_filename) printf("ymapfile: %s\n",cfg.ymap_filename);
333
334 image_x = malloc((cfg.rows)*sizeof(*image_x));
335 for(y=0;y<(cfg.rows);y++) image_x[y]= malloc((cfg.cols)*sizeof(*(image_x[y])));
336 image_y = malloc((cfg.rows)*sizeof(*image_y));
337 for(y=0;y<(cfg.rows);y++) image_y[y]= malloc((cfg.cols)*sizeof(*(image_y[y])));
338
339
340 switch(cfg.mode){
341 case FRONT: gen_front_maps(cfg,image_x,image_y); break;
342/* case FRONT235: gen_front235_maps(cfg,image_x,image_y); break;
343 case DOWN: gen_down_maps(cfg,image_x,image_y); break;
344 case SAMSUNG_GEAR_360: gen_samsung_gear_360_maps(cfg,image_x,image_y); break;
345 case THETAS: gen_thetas_maps(cfg,image_x,image_y); break;
346*/
347 default: printf("Camera mode not implemented\n"); exit(1);
348
349 }
350
351
352
353
354 printf("Writing files\n");
355 pgmWrite_ASCII(cfg.ymap_filename, cfg.rows,cfg.cols,image_y,cfg.ymap_filename);
356 pgmWrite_ASCII(cfg.xmap_filename, cfg.rows,cfg.cols,image_x,cfg.xmap_filename);
357
358 if(image_y){
359 for (y = 0; y<cfg.rows;y++) free(image_y[y]);
360 free(image_y);
361 }
362 if(image_x){
363 for (y = 0; y<cfg.rows;y++) free(image_x[y]);
364 free(image_x);
365 }
366
367
368 exit (0);
369}