static double calc_err(meta_parameters *meta, int line_lo, int line_hi, int samp_lo, int samp_hi, double *lats, double *lons) { int l = (line_lo + line_hi) * .5; int s = (samp_lo + samp_hi) * .5; double interp_lat, interp_lon, real_lat, real_lon; xy_interp(l, s, line_lo, line_hi, samp_lo, samp_hi, lats, lons, &interp_lat, &interp_lon); img_to_latlon(meta, l, s, &real_lat, &real_lon); asfPrintStatus(" Interp: (%f,%f)\n", interp_lat, interp_lon); asfPrintStatus(" Actual: (%f,%f)\n", real_lat, real_lon); return hypot(interp_lat - real_lat, interp_lon - real_lon); }
static double calc_err(meta_parameters *meta_sar, meta_parameters *meta_dem, int line_lo, int line_hi, int samp_lo, int samp_hi, double *lines, double *samps) { int l = (line_lo + line_hi) * .5; int s = (samp_lo + samp_hi) * .5; double interp_line, interp_samp, real_line, real_samp; xy_interp(l, s, line_lo, line_hi, samp_lo, samp_hi, lines, samps, &interp_line, &interp_samp); sar_to_dem(meta_sar, meta_dem, l, s, &real_line, &real_samp); asfPrintStatus(" Interp: (%f,%f)\n", interp_line, interp_samp); asfPrintStatus(" Actual: (%f,%f)\n", real_line, real_samp); return hypot(interp_line - real_line, interp_samp - real_samp); }
// Input: // meta_parameters *meta_sar-- SAR geometry to subset the DEM // const char *demImg -- DEM data filename // const char *demMeta -- DEM metadata filename // int pad -- number of lines to add at the top/bottom/left/right // double tolerance -- how accurate the approximation mapping needs to be, // in units of pixels // const char *output_name -- output filename (basename) // int test_mode -- adds checks for the accuracy of the mapping, and // does some unit testing // Output: // no output parameters, the output is the output_name files (.img and .meta) // Return Value: // return TRUE on success, FALSE on fail // int make_gr_dem_ext(meta_parameters *meta_sar, const char *demImg, const char *demMeta, int pad, double tolerance, const char *output_name, int test_mode) { if (test_mode) test_interp(); asfPrintStatus("Reading DEM...\n"); meta_parameters *meta_dem = meta_read(demMeta); float *demData = NULL; FloatImage *fi_dem = NULL; int dnl = meta_dem->general->line_count; int dns = meta_dem->general->sample_count; if (0) demData = read_dem(meta_dem, demImg); else fi_dem = float_image_new_from_metadata(meta_dem, demImg); if (demData) asfPrintStatus("Old method: reading entire DEM.\n"); if (fi_dem) asfPrintStatus("New method: float image\n"); if (demData && fi_dem) asfPrintError("Impossible.\n"); char *outImg = appendExt(output_name, ".img"); char *output_name_tmp, *outImgTmp; // do not do DEM smoothing if the DEM pixel size is better or close to the // SAR image's pixel size. int do_averaging = TRUE; if (meta_dem->general->y_pixel_size - 10 < meta_sar->general->y_pixel_size) do_averaging = FALSE; asfPrintStatus("Averaging: %s (DEM %f, SAR: %f)\n", do_averaging ? "YES" : "NO", meta_dem->general->y_pixel_size, meta_sar->general->y_pixel_size); if (do_averaging) { output_name_tmp = appendStr(output_name, "_unsmoothed"); outImgTmp = appendExt(output_name_tmp, ".img"); } else { output_name_tmp = STRDUP(output_name); outImgTmp = STRDUP(outImg); } // add the padding if requested meta_parameters *meta_out = meta_copy(meta_sar); meta_out->general->line_count += pad*2; meta_out->general->sample_count += pad*2; meta_out->general->start_line -= pad; meta_out->general->start_sample -= pad; // fixing up the output metadata. Note that we must keep the SAR section // intact since that specifies our geometry which is the whole point of // this exercise. strcpy(meta_out->general->basename, meta_dem->general->basename); strcpy(meta_out->general->sensor, MAGIC_UNSET_STRING); strcpy(meta_out->general->processor, MAGIC_UNSET_STRING); strcpy(meta_out->general->mode, MAGIC_UNSET_STRING); strcpy(meta_out->general->sensor_name, MAGIC_UNSET_STRING); meta_out->general->image_data_type = DEM; meta_out->general->radiometry = MAGIC_UNSET_INT; strcpy(meta_out->general->acquisition_date, meta_dem->general->acquisition_date); meta_out->general->orbit = MAGIC_UNSET_INT; meta_out->general->orbit_direction = MAGIC_UNSET_CHAR; meta_out->general->frame = MAGIC_UNSET_INT; meta_out->general->band_count = 1; strcpy(meta_out->general->bands, "DEM"); int nl = meta_out->general->line_count; int ns = meta_out->general->sample_count; // finding the right grid size int size = find_grid_size(meta_sar, meta_dem, 512, .1*tolerance); asfPrintStatus("Creating ground range image...\n"); float *buf = MALLOC(sizeof(float)*ns*size); FILE *fpOut = FOPEN(outImgTmp, "wb"); // these are for tracking the quality of the bilinear interp // not used if test_mode is false int num_out_of_tol = 0; int num_checked = 0; int num_bad = 0; double max_err = 0; double avg_err = 0; int ii, jj; for (ii=0; ii<nl; ii += size) { int line_lo = ii; int line_hi = ii + size; for (jj=0; jj<ns; jj += size) { double lines[4], samps[4]; int samp_lo = jj; int samp_hi = jj + size; get_interp_params(meta_sar, meta_dem, line_lo, line_hi, samp_lo, samp_hi, lines, samps); int iii, jjj; for (iii=0; iii<size; ++iii) { for (jjj=0; jjj<size && jj+jjj<ns; ++jjj) { int index = iii*ns + jj + jjj; assert(index < ns*size); double line_out, samp_out; xy_interp(ii+iii, jj+jjj, line_lo, line_hi, samp_lo, samp_hi, lines, samps, &line_out, &samp_out); // random checking of the quality of our interpolations if (test_mode && iii%11==0 && jjj%13==0) { double real_line, real_samp; sar_to_dem(meta_sar, meta_dem, ii+iii, jj+jjj, &real_line, &real_samp); double err = hypot(real_line - line_out, real_samp - samp_out); avg_err += err; if (err > max_err) max_err = err; if (err > tolerance) { asfPrintStatus("Out of tolerance at %d,%d: (%f,%f) vs (%f,%f) -> %f\n", ii+iii, jj+jjj, line_out, samp_out, real_line, real_samp, err); ++num_out_of_tol; } if (err > .5) { asfPrintStatus("Error is larger than 1 pixel!\n"); ++num_bad; } ++num_checked; } if (demData) buf[index] = interp_demData(demData, dnl, dns, line_out, samp_out); else if (fi_dem) buf[index] = interp_dem(fi_dem, line_out, samp_out); else asfPrintError("Oops.\n"); } } } put_float_lines(fpOut, meta_out, ii, size, buf); asfPrintStatus("Completed %.1f%% \r", 100.*ii/(double)nl); } asfPrintStatus("Completed 100%% \n"); if (test_mode) { asfPrintStatus("Tolerance was %f\n", tolerance); asfPrintStatus("%d/%d checked pixels had error exceeding tolerance. (%.1f%%)\n", num_out_of_tol, num_checked, 100.*num_out_of_tol/(double)num_checked); asfPrintStatus("%d/%d checked pixels had error larger than half a pixel. (%.1f%%)\n", num_bad, num_checked, 100.*num_bad/(double)num_checked); asfPrintStatus("Maximum error: %f pixels\n", max_err); avg_err /= (double)num_checked; asfPrintStatus("Average error: %f pixels\n", avg_err); } FCLOSE(fpOut); meta_write(meta_out, outImgTmp); meta_free(meta_out); meta_free(meta_dem); FREE(buf); FREE(demData); if (fi_dem) float_image_free(fi_dem); // now apply 3x3 filter if (do_averaging) { asfPrintStatus("Smoothing with 3x3 kernel ...\n"); smooth(outImgTmp, outImg, 3, EDGE_TRUNCATE); } FREE(outImg); FREE(outImgTmp); FREE(output_name_tmp); return FALSE; }
int geoid_adjust(const char *input_filename, const char *output_filename) { char *input_img = appendExt(input_filename, ".img"); char *input_meta = appendExt(input_filename, ".meta"); char *output_img = appendExt(output_filename, ".img"); char *output_meta = appendExt(output_filename, ".meta"); if (!fileExists(input_img)) asfPrintError("File not found: %s\n", input_img); if (!fileExists(input_meta)) asfPrintError("File not found: %s\n", input_meta); meta_parameters *meta = meta_read(input_meta); int nl = meta->general->line_count; int ns = meta->general->sample_count; int ii, jj; FILE *fpIn = FOPEN(input_img, "rb"); FILE *fpOut = FOPEN(output_img, "wb"); float *buf; // Two ways we can do this: // 1) call meta_get_latLon at every point // 2) call meta_get_latLon at certain points and interpolate between // We will use the first when we have a lat/lon image, and the second for // everything else. int latlon_image = meta->projection && meta->projection->type == LAT_LONG_PSEUDO_PROJECTION; double avg = 0.0; int num=0; asfPrintStatus("Performing geoid correction.\n"); asfPrintStatus(" Input file: %s\n", input_filename); asfPrintStatus(" Output file: %s\n", output_filename); if (latlon_image) { asfPrintStatus("Lat/Lon image, not using mapping interpolation.\n"); buf = MALLOC(sizeof(float)*ns); for (ii=0; ii<nl; ++ii) { get_float_line(fpIn, meta, ii, buf); for (jj=0; jj<ns; ++jj) { double lat, lon; meta_get_latLon(meta, ii, jj, 0, &lat, &lon); if (buf[jj] > -900 && buf[jj] != meta->general->no_data) { float ht = get_geoid_height(lat,lon); buf[jj] += ht; avg += ht; ++num; } } put_float_line(fpOut, meta, ii, buf); asfLineMeter(ii,nl); } } else { asfPrintStatus("Not a Lat/Lon image, using mapping interpolation.\n"); double tol = .0001; int size = find_grid_size(meta, 512, .1*tol); int test_mode = 1; buf = MALLOC(sizeof(float)*ns*size); // these are for tracking the quality of the bilinear interp // not used if test_mode is false int num_out_of_tol = 0; int num_checked = 0; int num_bad = 0; double max_err = 0; double avg_err = 0; for (ii=0; ii<nl; ii += size) { int line_lo = ii; int line_hi = ii + size; if (ii+size >= nl) size = nl-ii; get_float_lines(fpIn, meta, ii, size, buf); for (jj=0; jj<ns; jj += size) { double lats[4], lons[4]; int samp_lo = jj; int samp_hi = jj + size; get_interp_params(meta, line_lo, line_hi, samp_lo, samp_hi, lats, lons); int iii, jjj; for (iii=0; iii<size; ++iii) { for (jjj=0; jjj<size && jj+jjj<ns; ++jjj) { int kkk = iii*ns + jj + jjj; assert(kkk < ns*size); double lat, lon; xy_interp(ii+iii, jj+jjj, line_lo, line_hi, samp_lo, samp_hi, lats, lons, &lat, &lon); // random checking of the quality of our interpolations if (test_mode && iii%11==0 && jjj%13==0) { double real_lat, real_lon; img_to_latlon(meta, ii+iii, jj+jjj, &real_lat, &real_lon); double err = hypot(real_lat - lat, real_lon - lon); avg_err += err; if (err > max_err) max_err = err; if (err > .1*tol) { asfPrintStatus("Out of tolerance at %d,%d: (%f,%f) vs (%f,%f) -> %f\n", ii+iii, jj+jjj, lat, lon, real_lat, real_lon, err); ++num_out_of_tol; } if (err > tol) { asfPrintStatus("Error is larger than %f!\n", .01*tol); ++num_bad; } ++num_checked; } if (buf[kkk] > -900 && buf[kkk] != meta->general->no_data) { float ht = get_geoid_height(lat,lon); buf[kkk] += ht; avg += ht; ++num; } } } } put_float_lines(fpOut, meta, ii, size, buf); asfPrintStatus("Completed %.1f%% \r", 100.*ii/(double)nl); } asfPrintStatus("Completed 100%% \n"); } avg /= (double)(num); asfPrintStatus("Average correction: %f\n", avg); meta_write(meta, output_meta); meta_free(meta); FCLOSE(fpIn); FCLOSE(fpOut); FREE(buf); FREE(input_img); FREE(input_meta); FREE(output_img); FREE(output_meta); // success return 0; }