Example #1
0
/******************************************************************************
METHOD:  l8cfmask

PURPOSE:  the main routine for fmask in C

RETURN VALUE:
Type = int
Value           Description
-----           -----------
ERROR           An error occurred during processing of the l8cfmask
SUCCESS         Processing was successful

PROJECT:  Land Satellites Data System Science Research and Development (LSRD)
at the USGS EROS

HISTORY:
Date        Programmer       Reason
--------    ---------------  -------------------------------------
3/15/2013   Song Guo         Original Development
5/14/2013   Song Guo         Added in Polar Stereographic support
7/17/2013   Song Guo         Added in Map info 
8/15/2013   Song Guo         Modified to use TOA reflectance file 
                             as input instead of metadata file
Oct/2014    Ron Dilley       Modified to utilize the ESPA internal raw binary
                             file format

NOTES: type ./l8cfmask --help for information to run the code
******************************************************************************/
int
main (int argc, char *argv[])
{
    char errstr[MAX_STR_LEN];     /* error string */
    char *cptr = NULL;            /* pointer to the file extension */
    char *xml_name = NULL;        /* input XML filename */
    char directory[MAX_STR_LEN];  /* input/output data directory */
    char extension[MAX_STR_LEN];  /* input TOA file extension */
    int ib;                       /* band counters */
    Input_t *input = NULL;        /* input data and meta data */
    char envi_file[MAX_STR_LEN];  /* output ENVI file name */
    char scene_name[MAX_STR_LEN]; /* input data scene name */
    unsigned char **pixel_mask;   /* pixel mask */
    unsigned char **conf_mask;    /* confidence mask */
    int status;               /* return value from function call */
    float clear_ptm;          /* percent of clear-sky pixels */
    float t_templ = 0.0;      /* percentile of low background temperature */
    float t_temph = 0.0;      /* percentile of high background temperature */
    Output_t *output = NULL;  /* output structure and metadata */
    bool verbose;             /* verbose flag for printing messages */
    bool use_l8_cirrus;       /* should we use L8 cirrus cloud bit results? */
    int cldpix = 2;           /* Default buffer for cloud pixel dilate */
    int sdpix = 2;            /* Default buffer for shadow pixel dilate */
    float cloud_prob;         /* Default cloud probability */
    float sun_azi_temp = 0.0; /* Keep the original sun azimuth angle */
    int max_cloud_pixels; /* Maximum cloud pixel number in cloud division */
    Espa_internal_meta_t xml_metadata; /* XML metadata structure */
    Envi_header_t envi_hdr;            /* output ENVI header information */

    time_t now;
    time (&now);
    printf ("CFmask start_time=%s\n", ctime (&now));

    /* Read the command-line arguments, including the name of the input
       Landsat TOA reflectance product and the DEM */
    status = get_args (argc, argv, &xml_name, &cloud_prob, &cldpix,
                       &sdpix, &max_cloud_pixels, &use_l8_cirrus, &verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "calling get_args");
        CFMASK_ERROR (errstr, "main");
    }

    /* Validate the input metadata file */
    if (validate_xml_file (xml_name) != SUCCESS)
    {                           /* Error messages already written */
        CFMASK_ERROR (errstr, "main");
    }

    /* Initialize the metadata structure */
    init_metadata_struct (&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata (xml_name, &xml_metadata) != SUCCESS)
    {                           /* Error messages already written */
        CFMASK_ERROR (errstr, "main");
    }

    /* Verify supported satellites */
    if (strcmp (xml_metadata.global.satellite, "LANDSAT_8") != 0)
    {
        sprintf (errstr, "Unsupported satellite sensor");
        CFMASK_ERROR (errstr, "main");
    }

    /* Split the filename to obtain the directory, scene name, and extension */
    split_filename (xml_name, directory, scene_name, extension);
    if (verbose)
        printf ("directory, scene_name, extension=%s,%s,%s\n",
                directory, scene_name, extension);

    /* Open input file, read metadata, and set up buffers */
    input = OpenInput (&xml_metadata);
    if (input == NULL)
    {
        sprintf (errstr, "opening the TOA and brightness temp files in: %s",
                 xml_name);
        CFMASK_ERROR (errstr, "main");
    }

    if (verbose)
    {
        /* Print some info to show how the input metadata works */
        printf ("DEBUG: Number of input TOA bands: %d\n", input->nband);
        printf ("DEBUG: Number of input thermal bands: %d\n", 1);
        printf ("DEBUG: Number of input TOA lines: %d\n", input->size.l);
        printf ("DEBUG: Number of input TOA samples: %d\n", input->size.s);
        printf ("DEBUG: ACQUISITION_DATE.DOY is %d\n",
                input->meta.acq_date.doy);
        printf ("DEBUG: Fill value is %d\n", input->meta.fill);
        for (ib = 0; ib < input->nband; ib++)
        {
            printf ("DEBUG: Band %d-->\n", ib);
            printf ("DEBUG:   band satu_value_ref: %d\n",
                    input->meta.satu_value_ref[ib]);
            printf ("DEBUG:   band satu_value_max: %d\n",
                    input->meta.satu_value_max[ib]);
            printf ("DEBUG:   band gains: %f, band biases: %f\n",
                    input->meta.gain[ib], input->meta.bias[ib]);
        }
        printf ("DEBUG: Thermal Band (Band 10) -->\n");
        printf ("DEBUG:   therm_satu_value_ref: %d\n",
                input->meta.therm_satu_value_ref);
        printf ("DEBUG:   therm_satu_value_max: %d\n",
                input->meta.therm_satu_value_max);
        printf ("DEBUG:   therm_gain: %f, therm_bias: %f\n",
                input->meta.gain_th, input->meta.bias_th);

        printf ("DEBUG: SUN AZIMUTH is %f\n", input->meta.sun_az);
        printf ("DEBUG: SUN ZENITH is %f\n", input->meta.sun_zen);
    }

    /* If the scene is an ascending polar scene (flipped upside down), then
       the solar azimuth needs to be adjusted by 180 degrees.  The scene in
       this case would be north down and the solar azimuth is based on north
       being up clock-wise direction. Flip the south to be up will not change
       the actual sun location, with the below relations, the solar azimuth
       angle will need add in 180.0 for correct sun location */
    if (input->meta.ul_corner.is_fill &&
        input->meta.lr_corner.is_fill &&
        (input->meta.ul_corner.lat - input->meta.lr_corner.lat) < MINSIGMA)
    {
        /* Keep the original solar azimuth angle */
        sun_azi_temp = input->meta.sun_az;
        input->meta.sun_az += 180.0;
        if ((input->meta.sun_az - 360.0) > MINSIGMA)
            input->meta.sun_az -= 360.0;
        if (verbose)
            printf ("  Polar or ascending scene."
                    "  Readjusting solar azimuth by 180 degrees.\n"
                    "  New value: %f degrees\n", input->meta.sun_az);
    }

    /* Dynamic allocate the 2d mask memory */
    pixel_mask = (unsigned char **) allocate_2d_array (input->size.l,
                                                       input->size.s,
                                                       sizeof (unsigned char));
    if (pixel_mask == NULL)
    {
        sprintf (errstr, "Allocating pixel mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    conf_mask = (unsigned char **) allocate_2d_array (input->size.l,
                                                      input->size.s,
                                                      sizeof (unsigned char));
    if (conf_mask == NULL)
    {
        sprintf (errstr, "Allocating confidence mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    /* Initialize the mask to clear data */
    int row, col;
    for (row = 0; row < input->size.l; row++)
        for (col = 0; col < input->size.s; col++)
        {
            pixel_mask[row][col] = MASK_CLEAR_LAND;
            conf_mask[row][col] = CLOUD_CONFIDENCE_NONE;
        }

    /* Build the potential cloud, shadow, snow, water mask */
    status = potential_cloud_shadow_snow_mask (input, cloud_prob, &clear_ptm,
                                               &t_templ, &t_temph, pixel_mask,
                                               conf_mask, use_l8_cirrus,
                                               verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "processing potential_cloud_shadow_snow_mask");
        CFMASK_ERROR (errstr, "main");
    }

    printf ("Pcloud done, starting cloud/shadow match\n");

    /* Build the final cloud shadow based on geometry matching and
       combine the final cloud, shadow, snow, water masks into fmask
       the pixel_mask is a bit mask as input and a value mask as output */
    status = object_cloud_shadow_match (input, clear_ptm, t_templ, t_temph,
                                        cldpix, sdpix, max_cloud_pixels,
                                        pixel_mask, verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "processing object_cloud_and_shadow_match");
        CFMASK_ERROR (errstr, "main");
    }

    /* Reassign solar azimuth angle for output purpose if south up north
       down scene is involved */
    if (input->meta.ul_corner.is_fill &&
        input->meta.lr_corner.is_fill &&
        (input->meta.ul_corner.lat - input->meta.lr_corner.lat) < MINSIGMA)
        input->meta.sun_az = sun_azi_temp;

    /* Open the output file */
    output = OpenOutput (&xml_metadata, input);
    if (output == NULL)
    {                           /* error message already printed */
        sprintf (errstr, "Opening output file");
        CFMASK_ERROR (errstr, "main");
    }

    if (!PutOutput (output, pixel_mask))
    {
        sprintf (errstr, "Writing output fmask files\n");
        CFMASK_ERROR (errstr, "main");
    }

    /* Close the output file */
    if (!CloseOutput (output))
    {
        sprintf (errstr, "closing output file");
        CFMASK_ERROR (errstr, "main");
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct (&output->metadata.band[0], &xml_metadata.global,
                            &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Creating ENVI header structure.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Write the ENVI header */
    strcpy (envi_file, output->metadata.band[0].file_name);
    cptr = strchr (envi_file, '.');
    if (cptr == NULL)
    {
        sprintf (errstr, "error in ENVI header filename");
        CFMASK_ERROR (errstr, "main");
    }

    strcpy (cptr, ".hdr");
    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Writing ENVI header file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata (output->nband, output->metadata.band, xml_name)
        != SUCCESS)
    {
        sprintf (errstr, "Appending spectral index bands to XML file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Free the structure */
    if (!FreeOutput (output))
    {
        sprintf (errstr, "freeing output file structure");
        CFMASK_ERROR (errstr, "main");
    }

    output = OpenOutputConfidence (&xml_metadata, input);
    if (output == NULL)
    {                           /* error message already printed */
        sprintf (errstr, "Opening output file");
        CFMASK_ERROR (errstr, "main");
    }

    if (!PutOutput (output, conf_mask))
    {
        sprintf (errstr, "Writing output fmask files\n");
        CFMASK_ERROR (errstr, "main");
    }

    /* Close the output file */
    if (!CloseOutput (output))
    {
        sprintf (errstr, "closing output file");
        CFMASK_ERROR (errstr, "main");
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct (&output->metadata.band[0], &xml_metadata.global,
                            &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Creating ENVI header structure.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Write the ENVI header */
    strcpy (envi_file, output->metadata.band[0].file_name);
    cptr = strchr (envi_file, '.');
    if (cptr == NULL)
    {
        sprintf (errstr, "error in ENVI header filename");
        CFMASK_ERROR (errstr, "main");
    }

    strcpy (cptr, ".hdr");
    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Writing ENVI header file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata (output->nband, output->metadata.band, xml_name)
        != SUCCESS)
    {
        sprintf (errstr, "Appending spectral index bands to XML file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Free the structure */
    if (!FreeOutput (output))
    {
        sprintf (errstr, "freeing output file structure");
        CFMASK_ERROR (errstr, "main");
    }

    /* Free the metadata structure */
    free_metadata (&xml_metadata);

    /* Free the pixel mask */
    status = free_2d_array ((void **) pixel_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing pixel mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    status = free_2d_array ((void **) conf_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing confidence mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    /* Close the input file and free the structure */
    CloseInput (input);
    FreeInput (input);

    free (xml_name);

    printf ("Processing complete.\n");
    time (&now);
    printf ("CFmask end_time=%s\n", ctime (&now));

    return SUCCESS;
}
Example #2
0
/******************************************************************************
METHOD:  cfmask

PURPOSE:  the main routine for fmask in C

RETURN VALUE:
Type = int
Value           Description
-----           -----------
ERROR           An error occurred during processing of the cfmask
SUCCESS         Processing was successful

PROJECT:  Land Satellites Data System Science Research and Development (LSRD)
at the USGS EROS

HISTORY:
Date        Programmer       Reason
--------    ---------------  -------------------------------------
3/15/2013   Song Guo         Original Development
5/14/2013   Song Guo         Added in Polar Stereographic support
7/17/2013   Song Guo         Added in Map info 
8/15/2013   Song Guo         Modified to use TOA reflectance file 
                             as input instead of metadata file

NOTES: type ./cfmask --help for information to run the code
******************************************************************************/
int main (int argc, char *argv[])
{
    char errstr[MAX_STR_LEN];           /* error string */
    char lndth_name[MAX_STR_LEN];       /* ledaps Brightness Temperature file */
    char fmask_name[MAX_STR_LEN];       /* output fmask binary file name */
    char fmask_header[MAX_STR_LEN];     /* output fmask binary file header */
    char fmask_hdf_name[MAX_STR_LEN];   /* output fmask HDF file name */
    char fmask_hdf_hdr[MAX_STR_LEN];    /* output fmask HDF file header */
    char *lndcal_name = NULL;           /* input lndcal data filename */
    char directory[MAX_STR_LEN];        /* input/output data directory */
    char extension[MAX_STR_LEN];        /* input TOA file extension */
    int ib;                             /* band counters */
    char sds_names[NBAND_REFL_MAX][MAX_STR_LEN]; /* array of image SDS names */
    Input_t *input = NULL;              /* input data and meta data */
    char  scene_name[MAX_STR_LEN];      /* input data scene name */
    char *hdf_grid_name = "Grid";  /* name of the grid for HDF-EOS */
    unsigned char **cloud_mask;    /* cloud pixel mask */
    unsigned char **shadow_mask;   /* shadow pixel mask */
    unsigned char **snow_mask;     /* snow pixel mask */
    unsigned char **water_mask;    /* water pixel mask */
    int status;                    /* return value from function call */
    FILE *fd = NULL;               /* file pointer */
    float ptm;                     /* percent of clear-sky pixels */
    float t_templ = 0.0;     /* percentile of low background temperature */
    float t_temph = 0.0;     /* percentile of high background temperature */
    int out_sds_types[NUM_OUT_SDS];     /* array of image SDS types */
    char *sds_name="fmask_band";        /* Fmask hdf SDS name */
    Output_t *output = NULL;            /* output structure and metadata */
    bool verbose;            /* verbose flag for printing messages */
    bool write_binary;       /* should we write raw binary output? */
    bool no_hdf_output;      /* should we don't write HDF4 output file? */
    int cldpix = 2;          /* Default buffer for cloud pixel dilate */
    int sdpix = 2;           /* Default buffer for shadow pixel dilate */
    float cloud_prob;        /* Default cloud probability */
    Space_def_t space_def;   /* spatial definition information */
    float sun_azi_temp = 0.0;/* Keep the original sun azimuth angle */
  
    time_t now;
    time(&now);
    printf("CFmask start_time=%s\n",ctime(&now));

    /* Read the command-line arguments, including the name of the input
       Landsat TOA reflectance product and the DEM */
    status = get_args (argc, argv, &lndcal_name, &cloud_prob, &cldpix,
                       &sdpix, &write_binary, &no_hdf_output, &verbose);
    if (status != SUCCESS)
    { 
        sprintf (errstr, "calling get_args");
        ERROR (errstr, "main");
    }

    split_filename(lndcal_name, directory, scene_name, extension);
    if (verbose)
        printf("directory, scene_name, extension=%s,%s,%s\n", 
            directory, scene_name, extension);
    sprintf(lndcal_name, "%slndcal.%s.hdf", directory, scene_name);
    sprintf(lndth_name, "%slndth.%s.hdf", directory, scene_name);
    sprintf(fmask_name, "%sfmask.%s.img", directory, scene_name);
    sprintf(fmask_header, "%sfmask.%s.img.hdr", directory, scene_name);
    sprintf(fmask_hdf_name, "%sfmask.%s.hdf", directory, scene_name);
    if (verbose)
    {
        printf("lndcal_name, lndth_name = %s, %s\n", lndcal_name, lndth_name); 
        printf("fmask_name, fmask_header, fmask_hdf_name = %s, %s, %s\n", 
                fmask_name, fmask_header, fmask_hdf_name); 
    }

    /* Open input file, read metadata, and set up buffers */
    input = OpenInput(lndth_name, lndcal_name);
    if (input == NULL)
    {
        sprintf (errstr, "opening the input files: %s & %s", lndth_name,
                 lndcal_name);
        ERROR (errstr, "main");
    }

    /* Get the projection and spatial information from the input TOA
       reflectance product */
    status = get_space_def_hdf(&space_def, lndcal_name, hdf_grid_name);
    if (status != SUCCESS)
    {
        sprintf(errstr, "Reading spatial metadata from the HDF file: %s", 
               lndcal_name);
        ERROR (errstr, "main");
    }
    input->meta.zone = space_def.zone;

    if (verbose)
    {
        /* Print some info to show how the input metadata works */
        printf ("DEBUG: Number of input TOA bands: %d\n", input->nband);
        printf ("DEBUG: Number of input thermal bands: %d\n", 1);
        printf ("DEBUG: Number of input lines: %d\n", input->size.l);
        printf ("DEBUG: Number of input samples: %d\n", input->size.s);
        printf ("DEBUG: Number of input TOA lines: %d\n", input->toa_size.l);
        printf ("DEBUG: Number of input TOA samples: %d\n", input->toa_size.s);
        printf ("DEBUG: Provider is %s\n", input->meta.provider);
        printf ("DEBUG: Satellite is %s\n", input->meta.sat);
        printf ("DEBUG: Instrument is %s\n", input->meta.inst);
        printf ("DEBUG: ACQUISITION_DATE.DOY is %d\n", input->meta.acq_date.doy);
        printf ("DEBUG: WRS system is %s\n", input->meta.wrs_sys);
        printf ("DEBUG: Path is %d\n", input->meta.path);
        printf ("DEBUG: Row is %d\n", input->meta.row);
        printf ("DEBUG: Fill value is %d\n", input->meta.fill);
        for (ib = 0; ib < input->nband; ib++)
        {
            printf ("DEBUG: Band %d-->\n", ib);
            printf ("DEBUG:   SDS name is %s\n", input->sds[ib].name);
            printf ("DEBUG:   SDS rank: %d\n", input->sds[ib].rank);
            printf ("DEBUG:   band satu_value_ref: %d\n", 
                   input->meta.satu_value_ref[ib]);
            printf ("DEBUG:   band satu_value_max: %d\n", 
                   input->meta.satu_value_max[ib]);
            printf ("DEBUG:   band gains: %f, band biases: %f\n", 
                    input->meta.gain[ib], input->meta.bias[ib]);      
        }
        printf ("DEBUG: Thermal Band -->\n");
        printf ("DEBUG:   SDS name is %s\n", input->therm_sds.name);
        printf ("DEBUG:   SDS rank: %d\n", input->therm_sds.rank);
        printf ("DEBUG:   therm_satu_value_ref: %d\n", 
                   input->meta.therm_satu_value_ref);
        printf ("DEBUG:   therm_satu_value_max: %d\n", 
                   input->meta.therm_satu_value_max);
        printf ("DEBUG:   therm_gain: %f, therm_bias: %f\n", 
                input->meta.gain_th, input->meta.bias_th);

        printf("DEBUG: ROW is %d\n", input->meta.row);
        printf("DEBUG: PATH is %d\n", input->meta.path);
        printf("DEBUG: SUN AZIMUTH is %f\n", input->meta.sun_az);
        printf("DEBUG: SUN ZENITH is %f\n", input->meta.sun_zen);
        printf("DEBUG: Projection Zone is %d\n", input->meta.zone);

        printf("DEBUG: unit_ref is %s\n", input->meta.unit_ref);
        printf("DEBUG: valid_range_ref is %f & %f\n", 
           input->meta.valid_range_ref[0], 
           input->meta.valid_range_ref[1]);
    }

    /* If the scene is an ascending polar scene (flipped upside down), then
       the solar azimuth needs to be adjusted by 180 degrees.  The scene in
       this case would be north down and the solar azimuth is based on north
       being up clock-wise direction. Flip the south to be up will not change 
       the actual sun location, with the below relations, the solar azimuth
       angle will need add in 180.0 for correct sun location */
    if (input->meta.ul_corner.is_fill &&
        input->meta.lr_corner.is_fill &&
        (input->meta.ul_corner.lat - input->meta.lr_corner.lat) < MINSIGMA)
    {
        /* Keep the original solar azimuth angle */
        sun_azi_temp = input->meta.sun_az;
        input->meta.sun_az += 180.0;
        if ((input->meta.sun_az - 360.0) > MINSIGMA)
            input->meta.sun_az -= 360.0;
        if (verbose)
            printf ("  Polar or ascending scene.  Readjusting solar azimuth by "
                "180 degrees.\n  New value: %f degrees\n", input->meta.sun_az);
    }

    /* Copy the SDS names and QA SDS names from the input structure for the
       output structure, since we are simply duplicating the input */
    for (ib = 0; ib < input->nband; ib++)
        strcpy (&sds_names[ib][0], input->sds[ib].name);

    /* Dynamic allocate the 2d mask memory */
    cloud_mask = (unsigned char **)allocate_2d_array(input->size.l, 
                 input->size.s, sizeof(unsigned char)); 
    shadow_mask = (unsigned char **)allocate_2d_array(input->size.l, 
                 input->size.s, sizeof(unsigned char)); 
    snow_mask = (unsigned char **)allocate_2d_array(input->size.l, 
                 input->size.s, sizeof(unsigned char)); 
    water_mask = (unsigned char **)allocate_2d_array(input->size.l, 
                 input->size.s, sizeof(unsigned char)); 
    if (cloud_mask == NULL  || shadow_mask == NULL || snow_mask == NULL
        || water_mask == NULL)
    {
        sprintf (errstr, "Allocating mask memory");
        ERROR (errstr, "main");
    }

    /* Build the potential cloud, shadow, snow, water mask */
    status = potential_cloud_shadow_snow_mask(input, cloud_prob, &ptm,
             &t_templ, &t_temph, cloud_mask, shadow_mask, snow_mask, 
             water_mask, verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "processing potential_cloud_shadow_snow_mask");
        ERROR (errstr, "main");
    }

    printf("Pcloud done, starting cloud/shadow match\n");


    /* Build the final cloud shadow based on geometry matching and
       combine the final cloud, shadow, snow, water masks into fmask */
    status = object_cloud_shadow_match(input, ptm, t_templ, t_temph,
             cldpix, sdpix, cloud_mask, shadow_mask, snow_mask, water_mask,
             verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "processing object_cloud_and_shadow_match");
        ERROR (errstr, "main");
    }    

    status = free_2d_array((void **)shadow_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing mask memory");
        ERROR (errstr, "main");
    }
    status = free_2d_array((void **)snow_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing mask memory");
        ERROR (errstr, "main");
    }
    status = free_2d_array((void **)water_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing mask memory");
        ERROR (errstr, "main");
    }

    /* Reassign solar azimuth angle for output purpose if south up north 
       down scene is involved */
    if (input->meta.ul_corner.is_fill &&
        input->meta.lr_corner.is_fill &&
        (input->meta.ul_corner.lat - input->meta.lr_corner.lat) < MINSIGMA)
        input->meta.sun_az = sun_azi_temp;
   
    if (write_binary)
    {
        /* Create an ENVI header file for the binary fmask */
        status = write_envi_hdr(fmask_header, BINARY_FILE, input, &space_def);
        if (status != SUCCESS)
        {
            sprintf(errstr, "Creating ENVI header for binary fmask");
            ERROR (errstr, "main");
        }

        /* Open the mask file for writing */
        fd = fopen(fmask_name, "w"); 
        if (fd == NULL)
        {
            sprintf(errstr, "Opening report file: %s", fmask_name);
            ERROR (errstr, "main");
        }

        /* Write out the mask file */
        status = fwrite(&cloud_mask[0][0], sizeof(unsigned char),
            input->size.l * input->size.s, fd);
        if (status != input->size.l * input->size.s)
        {
            sprintf(errstr, "Writing to %s", fmask_name);
            ERROR (errstr, "main");
        }

        /* Close the mask file */
        status = fclose(fd);
        if (status)
        {
            sprintf(errstr, "Closing file %s", fmask_name);
            ERROR (errstr, "main");
        }
    }

    if (!no_hdf_output)
    {
        /* Create and open fmask HDF output file */
        if (!CreateOutput(fmask_hdf_name))
        {
            sprintf(errstr, "Creating HDF fmask output file");
            ERROR (errstr, "main");
        }
        output = OpenOutput (fmask_hdf_name, sds_name, &input->size);
        if (output == NULL)
        {
            sprintf (errstr, "opening output file - %s", fmask_hdf_name);
            ERROR(errstr, "main");
        }

        if (!PutOutput(output, cloud_mask))
        {
            sprintf (errstr, "Writing output fmask in HDF files\n");
            ERROR (errstr, "main");
        }

        if (!PutMetadata(output, input))
        {
            sprintf (errstr, "Writing output fmask metadata in HDF files\n");
            ERROR (errstr, "main");
        }

        /* Close the output file and free the structure */
        if (!CloseOutput (output))
        {
            sprintf (errstr, "closing output file - %s", fmask_hdf_name);
            ERROR(errstr, "main");
        }
        if (!FreeOutput (output))
        {
            sprintf (errstr, "freeing output file - %s", fmask_hdf_name);
            ERROR(errstr, "main");
        }

        /* Write the spatial information, after the file has been closed */
        out_sds_types[0] = DFNT_UINT8;
        status = put_space_def_hdf (&space_def, fmask_hdf_name, NUM_OUT_SDS, 
            out_sds_names, out_sds_types, hdf_grid_name);
        if (status != SUCCESS)
        {
            sprintf("Putting spatial metadata to the HDF file: "
            "%s", lndcal_name);
            ERROR (errstr, "main");
        }

        /* Write CFmask HDF header to add in envi map info */
        sprintf (fmask_hdf_hdr, "%s.hdr", fmask_hdf_name);
        status = write_envi_hdr (fmask_hdf_hdr, HDF_FILE, input, &space_def);
        if (status != SUCCESS)
        {
            sprintf(errstr, "Error writing the ENVI header for CFmask HDF hdr");
            ERROR (errstr, "main");
        }
    }

    /* Free the final output cloud_mask */
    status = free_2d_array((void **)cloud_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing mask memory");
        ERROR (errstr, "main");
    }

    /* Close the input file and free the structure */
    CloseInput (input);
    FreeInput (input);

    free(lndcal_name);
    printf ("Processing complete.\n");
    time(&now);
    printf("CFmask end_time=%s\n",ctime(&now));
    return (SUCCESS);
}
Example #3
0
/*****************************************************************************
METHOD:  cfmask

PURPOSE:  The main routine for fmask written in C

RETURN VALUE: Type = int
    Value           Description
    -----           -----------
    ERROR           An error occurred during processing of cfmask
    SUCCESS         Processing was successful
*****************************************************************************/
int
main (int argc, char *argv[])
{
    char *FUNC_NAME = "main";
    char *ext = NULL;            /* pointer to the file extension */
    char *xml_name = NULL;       /* input XML filename */
    char envi_file[MAX_STR_LEN]; /* output ENVI file name */
    char temp_file[MAX_STR_LEN]; /* temp file name */

    int status;
    int band_index;

    bool verbose;            /* verbose flag for printing messages */
    bool use_cirrus;         /* should we use Cirrus during determination? */
    bool use_thermal;        /* should we use Thermal during determination? */

    Input_t *input = NULL;    /* input data and meta data */
    Output_t *output = NULL;  /* output structure and metadata */
    Espa_internal_meta_t xml_metadata; /* XML metadata structure */
    Envi_header_t envi_hdr;            /* output ENVI header information */

    unsigned char *pixel_mask = NULL; /* pixel mask */
    unsigned char *conf_mask = NULL;  /* confidence mask */

    float clear_ptm;          /* percent of clear-sky pixels */
    float t_templ = 0.0;      /* percentile of low background temperature */
    float t_temph = 0.0;      /* percentile of high background temperature */

    int cldpix = 2;           /* Default buffer for cloud pixel dilate */
    int sdpix = 2;            /* Default buffer for shadow pixel dilate */
    float cloud_prob;         /* Default cloud probability */
    float sun_azi_temp = 0.0; /* Keep the original sun azimuth angle */

    int pixel_count;
    int pixel_index;

    time_t now;
    time(&now);

    /* Read the command-line arguments, including the name of the input
       Landsat TOA reflectance product and the DEM */
    status = get_args(argc, argv, &xml_name, &cloud_prob, &cldpix,
                      &sdpix, &use_cirrus, &use_thermal, &verbose);
    if (status != SUCCESS)
    {
        RETURN_ERROR("calling get_args", FUNC_NAME, EXIT_FAILURE);
    }

    printf("CFmask start_time=%s\n", ctime(&now));

    /* Validate the input metadata file */
    if (validate_xml_file(xml_name) != SUCCESS)
    {
        RETURN_ERROR("XML validation error", FUNC_NAME, EXIT_FAILURE);
    }

    /* Initialize the metadata structure */
    init_metadata_struct(&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata(xml_name, &xml_metadata) != SUCCESS)
    {
        RETURN_ERROR("XML parsing error", FUNC_NAME, EXIT_FAILURE);
    }

    /* Open input file, read metadata, and set up buffers */
    input = OpenInput(&xml_metadata, use_thermal);
    if (input == NULL)
    {
        RETURN_ERROR("opening input data specified in input XML",
                     FUNC_NAME, EXIT_FAILURE);
    }

    if (verbose)
    {
        /* Print some info to show how the input metadata works */
        printf("Number of input TOA bands: %d\n", input->num_toa_bands);
        printf("Number of input thermal bands: %d\n", 1);
        printf("Number of input TOA lines: %d\n", input->size.l);
        printf("Number of input TOA samples: %d\n", input->size.s);
        printf("Fill value is %d\n", input->meta.fill);
        for (band_index = 0; band_index < MAX_BAND_COUNT; band_index++)
        {
            printf("Band %d-->\n", band_index);
            if (input->satellite != IS_LANDSAT_8)
            {
                /* Landsat 8 doesn't have saturation issues */
                printf("  band satu_value_ref: %d\n",
                       input->meta.satu_value_ref[band_index]);
                printf("  band satu_value_max: %d\n",
                       input->meta.satu_value_max[band_index]);
            }
            printf("  band gain: %f, band bias: %f\n",
                   input->meta.gain[band_index], input->meta.bias[band_index]);
        }

        printf("SUN AZIMUTH is %f\n", input->meta.sun_az);
        printf("SUN ZENITH is %f\n", input->meta.sun_zen);
    }

    /* If the scene is an ascending polar scene (flipped upside down), then
       the solar azimuth needs to be adjusted by 180 degrees.  The scene in
       this case would be north down and the solar azimuth is based on north
       being up clock-wise direction. Flip the south to be up will not change
       the actual sun location, with the below relations, the solar azimuth
       angle will need add in 180.0 for correct sun location */
    if (input->meta.ul_corner.lat < input->meta.lr_corner.lat)
    {
        /* Keep the original solar azimuth angle */
        sun_azi_temp = input->meta.sun_az;
        input->meta.sun_az += 180.0;
        if (input->meta.sun_az > 360.0)
        {
            input->meta.sun_az -= 360.0;
        }
        if (verbose)
        {
            printf("Polar or ascending scene."
                    "  Readjusting solar azimuth by 180 degrees.\n"
                    "  New value: %f degrees\n", input->meta.sun_az);
        }
    }

    pixel_count = input->size.l * input->size.s;

    /* Dynamic allocate the 2d mask memory */
    pixel_mask = calloc(pixel_count, sizeof(unsigned char));
    if (pixel_mask == NULL)
    {
        RETURN_ERROR("Allocating pixel mask memory", FUNC_NAME, EXIT_FAILURE);
    }

    conf_mask = calloc(pixel_count, sizeof(unsigned char));
    if (conf_mask == NULL)
    {
        RETURN_ERROR("Allocating confidence mask memory",
                     FUNC_NAME, EXIT_FAILURE);
    }

    /* Initialize the mask to clear data */
    for (pixel_index = 0; pixel_index < pixel_count; pixel_index++)
    {
        pixel_mask[pixel_index] = CF_NO_BITS;
        conf_mask[pixel_index] = CLOUD_CONFIDENCE_NONE;
    }

    /* Build the potential cloud, shadow, snow, water mask */
    status = potential_cloud_shadow_snow_mask(input, cloud_prob, &clear_ptm,
                                              &t_templ, &t_temph, pixel_mask,
                                              conf_mask, use_cirrus,
                                              use_thermal, verbose);
    if (status != SUCCESS)
    {
        RETURN_ERROR("processing potential_cloud_shadow_snow_mask",
                     FUNC_NAME, EXIT_FAILURE);
    }
    printf("Potential Cloud Shadow: Done\n");

    /* Build the final cloud shadow based on geometry matching and
       combine the final cloud, shadow, snow, water masks into fmask
       the pixel_mask is a bit mask as input and a value mask as output */
    int data_count = 0;
    status = object_cloud_shadow_match(input, clear_ptm, t_templ, t_temph,
                                       cldpix, sdpix, pixel_mask, &data_count,
                                       use_thermal, verbose);
    if (status != SUCCESS)
    {
        RETURN_ERROR("processing object_cloud_and_shadow_match",
                     FUNC_NAME, EXIT_FAILURE);
    }
    printf("Object Cloud Shadow Matching: Done\n");

    /* Convert the pixel_mask to a value mask
       Also retrieve and report statistics */
    float clear_percent = 0; /* Percent of clear pixels in the image data */
    float cloud_percent = 0; /* Percent of cloud pixels in the image data */
    float cloud_shadow_percent = 0; /* Percent of cloud shadow pixels in the
                                       image data */
    float water_percent = 0; /* Percent of water pixels in the image data */
    float snow_percent = 0;  /* Percent of snow pixels in the image data */
    convert_and_generate_statistics(verbose, pixel_mask,
                                    input->size.l * input->size.s,
                                    data_count, &clear_percent,
                                    &cloud_percent, &cloud_shadow_percent,
                                    &water_percent, &snow_percent);
    printf("Statistics Generation: Done\n");

    /* Reassign solar azimuth angle for output purpose if south up north
       down scene is involved */
    if (input->meta.ul_corner.lat < input->meta.lr_corner.lat)
    {
        input->meta.sun_az = sun_azi_temp;
    }

    /* Open the output file */
    output = OpenOutputCFmask(&xml_metadata, input, clear_percent,
                              cloud_percent, cloud_shadow_percent,
                              water_percent, snow_percent);
    if (output == NULL)
    {
        RETURN_ERROR("Opening output file", FUNC_NAME, EXIT_FAILURE);
    }

    if (!PutOutput(output, pixel_mask))
    {
        RETURN_ERROR("Writing output fmask files", FUNC_NAME, EXIT_FAILURE);
    }

    /* Close the output file */
    if (!CloseOutput(output))
    {
        RETURN_ERROR("closing output file", FUNC_NAME, EXIT_FAILURE);
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct(&output->metadata.band[0], &xml_metadata.global,
                           &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Creating ENVI header structure.", FUNC_NAME,
                     EXIT_FAILURE);
    }

    /* Write the ENVI header */
    snprintf(temp_file, sizeof(temp_file), "%s",
             output->metadata.band[0].file_name);
    ext = strrchr(temp_file, '.');
    if (ext == NULL)
    {
        RETURN_ERROR("error in ENVI header filename", FUNC_NAME, EXIT_FAILURE);
    }

    ext[0] = '\0';
    snprintf(envi_file, sizeof(envi_file), "%s.hdr", temp_file);
    if (write_envi_hdr(envi_file, &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Writing ENVI header file.", FUNC_NAME, EXIT_FAILURE);
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata(output->nband, output->metadata.band, xml_name)
        != SUCCESS)
    {
        RETURN_ERROR("Appending spectral index bands to XML file.",
                     FUNC_NAME, EXIT_FAILURE);
    }

    /* Free the structure */
    if (!FreeOutput(output))
    {
        RETURN_ERROR("freeing output file structure", FUNC_NAME, EXIT_FAILURE);
    }

    output = OpenOutputConfidence(&xml_metadata, input);
    if (output == NULL)
    {
        RETURN_ERROR("Opening output file", FUNC_NAME, EXIT_FAILURE);
    }

    if (!PutOutput(output, conf_mask))
    {
        RETURN_ERROR("Writing output fmask files", FUNC_NAME, EXIT_FAILURE);
    }

    /* Close the output file */
    if (!CloseOutput(output))
    {
        RETURN_ERROR("closing output file", FUNC_NAME, EXIT_FAILURE);
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct(&output->metadata.band[0], &xml_metadata.global,
                           &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Creating ENVI header structure.", FUNC_NAME,
                     EXIT_FAILURE);
    }

    /* Write the ENVI header */
    snprintf(temp_file, sizeof(temp_file), "%s",
             output->metadata.band[0].file_name);
    ext = strrchr(temp_file, '.');
    if (ext == NULL)
    {
        RETURN_ERROR("error in ENVI header filename", FUNC_NAME, EXIT_FAILURE);
    }

    ext[0] = '\0';
    snprintf(envi_file, sizeof(envi_file), "%s.hdr", temp_file);
    if (write_envi_hdr(envi_file, &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Writing ENVI header file.", FUNC_NAME, EXIT_FAILURE);
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata(output->nband, output->metadata.band,
                        xml_name) != SUCCESS)
    {
        RETURN_ERROR("Appending spectral index bands to XML file.",
                     FUNC_NAME, EXIT_FAILURE);
    }

    /* Free the structure */
    if (!FreeOutput(output))
    {
        RETURN_ERROR("freeing output file structure", FUNC_NAME, EXIT_FAILURE);
    }

    /* Free the metadata structure */
    free_metadata(&xml_metadata);

    /* Free the pixel mask */
    free(pixel_mask);
    pixel_mask = NULL;
    free(conf_mask);
    conf_mask = NULL;

    /* Close the input file and free the structure */
    CloseInput(input);
    FreeInput(input);

    free(xml_name);
    xml_name = NULL;

    printf("Processing complete.\n");
    time(&now);
    printf("CFmask end_time=%s\n", ctime(&now));

    return SUCCESS;
}