/* ptrwarp.c: Pencigraphic Toolkit's Radial WARP about specified center ptwarp.c is part of pt-1.0 see http://wearcam.org/pencigraphy or see http://www-white.media.mit.edu/~steve/pencigraphy ptrwarp [-w] [-z] [-l int] [-a int] [-b int] [-c int] [-d] [-e outfile] [-o outfile] [infile] -w : Allow outfiles to overwrite existing files (if used, this must be the first flag equivalent to usage with >! instead of just > -l : use bilinear interpolation instead of default (defualt is bicubic interpolation) -m float : how far down center of aberration is located -n float : how far across center of aberration is located -a float : first (r^1) polynomial coeff -b float : second (r^3) polynomial coeff -c float : third (r^5) polynomial coeff -d : assume image has been de-interlaced and is FAT (anisotropic axes) -o outfile : Save the file after lines have been removed in specified directory infile : Name of original file other examples of file i/o -i3 pic.ppm : specify pic000.ppm, pic001.ppm... (pic%03d.ppm) -i170:4:290 pic.ppm: specifies pic170.ppm, pic174.ppm,... pic290.ppm -i3 pic000.ppm : only numeric globbing (??? must be 3 digit NUMBER) -i3 pic???.ppm : -i3 "170:4:290" pic.jpg ... need to determine which will work across largest variety architectures (may simplify/robustify code and only support some of above) -o3 pic : similar to above Lee Campbell, velocity map Sourabh Niyogi, bilinear John Y.A. Wang, Eero Simoncelli, bicubic Stephen Intille, file i/o (code no longer used) Steve Mann, rewrote for HP, channels, time, opt. Nat Friedman pnm support, savewarp, loadwarp */ #include #include #include #include #include #include #include #include #include #include #include /* Interpolation methods */ #define BILINEAR_INTERP 1 #define BICUBIC_INTERP 2 /* strdup() isn't sufficiently ubiquitous */ char * my_strdup(char * s) { char * dup_s; dup_s=(char *)malloc(sizeof(char)*(strlen(s)+1)); strcpy(dup_s, s); return dup_s; } int my_strcasecmp(char * s1, char * s2) { while (1) { if (*s1!=*s2) { if (tolower(*s1)!=tolower(*s2)) return *s1-*s2; } else if (*s1=='\0') break; s1++; s2++; } return 0; } void usage(char *programname) { fprintf(stderr, "use: %s [{inputfile,-i3 pic.ppm, -i pic???.ppm}] " "[{-o outputfile,-03 picw.ppm, -i pic???.ppm}] " "-m center_m -n center_n -a float -b float -c float [-w] [-l] " "[-p]\n",programname); exit(0); /* EXIT_SUCCESS = 0 (could also use) */ } void parse_command_line(int argc, char ** argv, int * num_input_files, char *** input_filename, char ** output_filename, int * use_approx_warp_map, int * overwrite_files, int * interp_method, int * deinterl, int * load_warp, int * make_warp, char ** warp_filename, int * proc_image, float * x0, float * y0, float * a1, float * a2, float * a3, int * M, int * N) { int oflag=0; int i; if (argc<2 && isatty(0)) /* STDIN_FILENO = 0 (stdin file descriptor) */ usage(argv[0]); for (i=1;i 255 */ if (*max_val>255) { fprintf(stderr, "get_image_params: Sorry, we don't support maximum " "colour component values greater than 255 yet.\n"); exit(0); } } void read_image(FILE * ifs, int N, int M, int bytes_pixel, int max_val, unsigned char ** image) { int bytes; int i; *image=(unsigned char *)malloc(sizeof(char)*bytes_pixel*N*M); bytes=fread(*image, bytes_pixel, N*M, ifs); bytes*=bytes_pixel; if (bytes!=N*M*bytes_pixel) { if (ferror(ifs)) { fprintf(stderr, "read_image: error reading image: %s\n", strerror(errno)); exit(0); } else if (feof(ifs)) { fprintf(stderr, "read_image: reached end of input file " " prematurely! Read %d bytes; wanted %d.\n", bytes, N*M*bytes_pixel); exit(0); } } /* Rescale the image if necessary */ if (max_val!=255) for(i=0;i1e-5); i++) { /* newton loop until error is small */ r = radius + rguess; r2 = r*r; /* f = radius - (a1*r + a2*r2 + a3*r*r2); */ /* fprime = -(a1 + 2*a2*r + 3*a3*r2); */ f = radius - (a1 + (a2 + a3*r2)*r2)*r; fprime = -(a1 + (3*a2 + 5*a3*r2)*r2); rgold = rguess; rguess = .9*(rguess - f/fprime); } i = (y * N + x); (*warp_map_x)[i] = -(xx/radius)*rguess; if (deinterl != 1) (*warp_map_y)[i] = -(yy/radius)*rguess; else (*warp_map_y)[i] = -(yy/(radius*2))*rguess; cc++; } } } /* bilinear interpolation code from sourabh */ void bilinear_warp(unsigned char * im, unsigned char ** out, float * vx, float * vy, int N, int M) { int x, y; float xpf, ypf; int xpi, ypi; int xbound, ybound; float dx, dy, ans; *out=(unsigned char *)malloc(sizeof(char)*N*M); xbound = N-1; ybound = M-1; for (y=0; y xbound) || ( (ypi+1) > ybound) ) *((*out)+y*N+x) = *(im+y*N+x); else { dx = xpf-(float)xpi; dy = ypf-(float)ypi; ans = (1-dx) * (1-dy) * (*(im + ypi * N + xpi)) + dx * (1-dy) * (*(im + ypi * N + xpi + 1)) + (1-dx) * dy * (*(im+(ypi+1) * N + xpi)) + dx * dy * (*(im+(ypi+1) * N + xpi + 1)); if (ans > 255) ans = (float)255; if (ans < 0) ans = 0; *((*out)+y*N+x) = ((unsigned char) (ans + 0.5)); } } } /* John/Eero's warper, for control expt. */ void bicube_warp(unsigned char * im, unsigned char ** res, float * wx, float *wy, int N, int M) { register unsigned char *im_ptr; /* accessed 38x in loop */ register int base; /* accessed 30x in loop */ register float frac, temp; /* accessed 20x in loop */ register float frac2, frac3; /* accessed 10x in loop */ int x_inbounds_1, x_inbounds0, x_inbounds1, x_inbounds2; /* 6x in loop */ register float x_coeff_1, x_coeff0, x_coeff1, x_coeff2; /* 5x in loop */ register float res_val; register int i,j,trunc; register float xfrac,xbase,yfrac,ybase; float x_off, y_off; *res=(unsigned char *)malloc(sizeof(char)*N*M); x_off = (float)((N - 1) / 2.0); y_off = (float)((M - 1) / 2.0); for(j=0; j= 0) && ((xbase + 0) < N)) && (((ybase) >= 0) && ((ybase + 0) < M))) { res_val = 0.0; frac = xfrac - xbase; frac2 = frac*frac; frac3 = frac*frac2; base = xbase - 1; im_ptr = im + base; x_inbounds_1 = ((base >= 0) && (base < N))?1:0; if (x_inbounds_1) x_coeff_1 = (frac2/2.0 - frac/3.0 - frac3/6.0); base++; x_inbounds0 = ((base >= 0) && (base < N))?1:0; if (x_inbounds0) x_coeff0 = (1.0 - frac/2.0 - frac2 + frac3/2.0); base++; x_inbounds1 = ((base >= 0) && (base < N))?1:0; if (x_inbounds1) x_coeff1 = (frac + frac2/2.0 - frac3/2.0); base++; x_inbounds2 = ((base >= 0) && (base < N))?1:0; if (x_inbounds2) x_coeff2 = (frac3/6.0 - frac/6.0); frac = yfrac - ybase; frac2 = frac*frac; frac3 = frac*frac2; base = ybase - 1 ; im_ptr += base*N; if ((base >= 0) && (base < M)) { temp = 0.0; if (x_inbounds_1) temp += x_coeff_1 * *im_ptr; im_ptr++; if (x_inbounds0) temp += x_coeff0 * *im_ptr; im_ptr++; if (x_inbounds1) temp += x_coeff1 * *im_ptr; im_ptr++; if (x_inbounds2) temp += x_coeff2 * *im_ptr; im_ptr -= 3; res_val += temp * (frac2/2.0 - frac/3.0 - frac3/6.0); } base++; im_ptr += N; if ((base >= 0) && (base < M)) { temp = 0.0; if (x_inbounds_1) temp += x_coeff_1 * *im_ptr; im_ptr++; if (x_inbounds0) temp += x_coeff0 * *im_ptr; im_ptr++; if (x_inbounds1) temp += x_coeff1 * *im_ptr; im_ptr++; if (x_inbounds2) temp += x_coeff2 * *im_ptr; im_ptr -= 3; res_val += temp * (1 - frac/2.0 - frac2 + frac3/2.0); } base++; im_ptr += N; if ((base >= 0) && (base < M)) { temp = 0.0; if (x_inbounds_1) temp += x_coeff_1 * *im_ptr; im_ptr++; if (x_inbounds0) temp += x_coeff0 * *im_ptr; im_ptr++; if (x_inbounds1) temp += x_coeff1 * *im_ptr; im_ptr++; if (x_inbounds2) temp += x_coeff2 * *im_ptr; im_ptr -= 3; res_val += temp * (frac + frac2/2.0 - frac3/2.0); } base++; im_ptr += N; if ((base >= 0) && (base < M)) { temp = 0.0; if (x_inbounds_1) temp += x_coeff_1 * *im_ptr; im_ptr++; if (x_inbounds0) temp += x_coeff0 * *im_ptr; im_ptr++; if (x_inbounds1) temp += x_coeff1 * *im_ptr; im_ptr++; if (x_inbounds2) temp += x_coeff2 * *im_ptr; im_ptr -= 3; res_val += temp * (frac3/6.0 - frac/6.0); } trunc = ((int) (res_val + 0.5)); if (trunc > 255) trunc = 255; if (trunc < 0) trunc = 0; *(*res) = trunc; } else { *(*res) = im[j*N + i]; } (*res)++; } } int main(int argc, char ** argv) { /* Some options... */ int use_approx_warp_map=0, interp_method=BILINEAR_INTERP, deinterl=0, overwrite_files=0, save_warp=0, load_warp=0, proc_image=1; char * output_filename = NULL; char * output_postfix = NULL; /* input_filenames is the list of input files to process */ char ** input_filenames = NULL; /* input_filename is the name of the file currently being processed */ char * input_filename=NULL; char * map_filename = NULL; int num_input_files=0; /* Spherical abberation correction paramaters */ float x0=0.0, y0=0.0, a1=0.0, a2=0.0, a3=0.0; /* Buffers to hold the images */ unsigned char *input_image, *output_image; unsigned char *input_image_r, *input_image_g, *input_image_b; unsigned char *output_image_r, *output_image_b, *output_image_g; /* Buffers to hold the warp map */ float * warp_map_x, * warp_map_y; /* Image paramaters */ int N, M, bytes_pixel, max_val; int first_N, first_M, first_bytes_pixel; /* The input file */ FILE * ifs=stdin; int input_file_num; parse_command_line(argc, argv, &num_input_files, &input_filenames, &output_filename, &use_approx_warp_map, &overwrite_files, &interp_method, &deinterl, &load_warp, &save_warp, &map_filename, &proc_image, &x0, &y0, &a1, &a2, &a3, &N, &M); if (!proc_image) { if (use_approx_warp_map) make_warp_map_approx(x0, y0, a1, a2, a3, N, M, &warp_map_x, &warp_map_y, deinterl); else make_warp_map(x0, y0, a1, a2, a3, N, M, &warp_map_x, &warp_map_y, deinterl); if (save_warp) save_warp_map(map_filename, warp_map_x, warp_map_y, N, M, a1, a2, a3, x0, y0); exit (0); } if (num_input_files>1) { output_postfix=(char *)my_strdup(output_filename); free(output_filename); } for (input_file_num=0;input_file_num1) { if (input_file_num) free(output_filename); output_filename=(char *)malloc(sizeof(char)* (strlen(output_postfix)+ strlen(input_filename)+1)); strcpy(output_filename, input_filename); strcat(output_filename, output_postfix); } if (!overwrite_files) check_output_file_name(output_filename); if (input_filename) if ((ifs=fopen(input_filename, "r"))==NULL) { fprintf(stderr, "Cannot open %s.\n", input_filename); exit(0); } fprintf(stderr, "\tGetting input paramaters for %s...\n", input_filename); get_image_params(ifs, &bytes_pixel, &N, &M, &max_val); fprintf(stderr,"\t%s: successfully read %d by %d image\n",argv[0],M,N); if (input_file_num && ((first_N!=N) || (first_M!=M) || (first_bytes_pixel!=bytes_pixel))) { fprintf(stderr, "%s has different dimensions/format than " "the first image!\n", input_filename); exit(0); } /* Only generate/load the warp map once... */ if (input_file_num==0) { first_N=N; first_M=M; first_bytes_pixel=bytes_pixel; if (!load_warp) fprintf(stderr, "\tGenerating %rwarp map...\n", use_approx_warp_map ? "approximate " : ""); else fprintf(stderr, "\tLoading warp map %s...\n", map_filename); if (load_warp) load_warp_map(map_filename, &warp_map_x, &warp_map_y, N, M); else if (use_approx_warp_map) make_warp_map_approx(x0, y0, a1, a2, a3, N, M, &warp_map_x, &warp_map_y, deinterl); else make_warp_map(x0, y0, a1, a2, a3, N, M, &warp_map_x, &warp_map_y, deinterl); if (save_warp) save_warp_map(map_filename, warp_map_x, warp_map_y, N, M, a1, a2, a3, x0, y0); } fprintf(stderr, "\tReading %s...\n", input_filename); read_image(ifs, N, M, bytes_pixel, max_val, &input_image); fprintf(stderr, "\tUsing %s interpolation to warp %s...", (interp_method==BILINEAR_INTERP) ? "bilinear" : "bicubic", input_filename); fflush(stderr); if (bytes_pixel==3) { split_image(input_image, &input_image_r, &input_image_g, &input_image_b, N, M); free(input_image); if (interp_method==BILINEAR_INTERP) { fprintf(stderr, "red "); fflush(stderr); bilinear_warp(input_image_r, &output_image_r, warp_map_x, warp_map_y, N, M); fprintf(stderr, "green "); fflush(stderr); bilinear_warp(input_image_g, &output_image_g, warp_map_x, warp_map_y, N, M); fprintf(stderr, "blue\n"); fflush(stderr); bilinear_warp(input_image_b, &output_image_b, warp_map_x, warp_map_y, N, M); } else { fprintf(stderr, "red "); fflush(stderr); bicube_warp(input_image_r, &output_image_r, warp_map_x, warp_map_y, N, M); fprintf(stderr, "green "); fflush(stderr); bicube_warp(input_image_g, &output_image_g, warp_map_x, warp_map_y, N, M); fprintf(stderr, "blue\n"); fflush(stderr); bicube_warp(input_image_b, &output_image_b, warp_map_x, warp_map_y, N, M); } join_image(&output_image, output_image_r, output_image_g, output_image_b, N, M); } else if (interp_method==BILINEAR_INTERP) bilinear_warp(input_image, &output_image, warp_map_x, warp_map_y, N, M); else bicube_warp(input_image, &output_image, warp_map_x, warp_map_y, N, M); fprintf(stderr, "\tWriting output image %s...\n", output_filename); write_image(output_filename, N, M, bytes_pixel, output_image); } exit(0); }