| 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’. */
|
|---|
| 15 | static int verbose_flag;
|
|---|
| 16 |
|
|---|
| 17 | typedef struct double2{
|
|---|
| 18 | double x;
|
|---|
| 19 | double y;
|
|---|
| 20 | }double2;
|
|---|
| 21 | typedef struct double3{
|
|---|
| 22 | double x;
|
|---|
| 23 | double y;
|
|---|
| 24 | double z;
|
|---|
| 25 | }double3;
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 | enum CameraMode {
|
|---|
| 29 | FRONT,
|
|---|
| 30 | FRONT235,
|
|---|
| 31 | BACK,
|
|---|
| 32 | UP,
|
|---|
| 33 | DOWN,
|
|---|
| 34 | SAMSUNG_GEAR_360,
|
|---|
| 35 | THETAS
|
|---|
| 36 | };
|
|---|
| 37 |
|
|---|
| 38 | typedef 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 |
|
|---|
| 55 | configuration 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 |
|
|---|
| 217 | int 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 | */
|
|---|
| 275 | double2 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 |
|
|---|
| 306 | void 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 |
|
|---|
| 322 | int
|
|---|
| 323 | main (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 | }
|
|---|