/****************************************************************************** MODULE: object_cloud_shadow_match PURPOSE: Identify the final shadow pixels by doing a geometric cloud and shadow matching which ends in with the maximum cloud and shadow similarity RETURN: 0 on success -1 on error HISTORY: Date Programmer Reason -------- --------------- ------------------------------------- 3/15/2013 Song Guo Original Development NOTES: ******************************************************************************/ int object_cloud_shadow_match ( Input_t *input, float ptm, float t_templ, float t_temph, int cldpix, int sdpix, unsigned char **cloud_mask, unsigned char **shadow_mask, unsigned char **snow_mask, unsigned char **water_mask, unsigned char **final_mask, bool verbose ) { char errstr[MAX_STR_LEN]; int nrows = input->size.l; int ncols = input->size.s; int row; int col = 0; float sun_ele; float sun_ele_rad; float sun_tazi; float sun_tazi_rad; int sub_size = 30; int status; /* Dynamic memory allocation */ unsigned char **cloud_cal; unsigned char **shadow_cal; unsigned char **boundary_test; cloud_cal = (unsigned char **)ias_misc_allocate_2d_array(input->size.l, input->size.s, sizeof(unsigned char)); shadow_cal = (unsigned char **)ias_misc_allocate_2d_array( input->size.l, input->size.s, sizeof(unsigned char)); boundary_test = (unsigned char **)ias_misc_allocate_2d_array( input->size.l, input->size.s, sizeof(unsigned char)); if (cloud_cal == NULL || shadow_cal == NULL || boundary_test == NULL) { sprintf (errstr, "Allocating mask memory"); ERROR (errstr, "cloud/shadow match"); } /* Read in potential mask ... */ /* Solar elevation angle */ sun_ele = 90 - input->meta.sun_zen; sun_ele_rad = (PI / 180.0) * sun_ele; /* Solar azimuth angle */ sun_tazi = input->meta.sun_az - 90; sun_tazi_rad = (PI / 180.0) * sun_tazi; int cloud_counter = 0; int boundary_counter = 0; float revised_ptm; for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { if (cloud_mask[row][col] == 1) cloud_counter++; /* Boundary layer includes both cloud_mask equals 0 and 1 */ if (cloud_mask[row][col] < 255) { boundary_test[row][col] = 1; boundary_counter++; } else boundary_test[row][col] = 0; } } /* Revised percent of cloud on the scene after plcloud */ revised_ptm = (float)cloud_counter / (float)boundary_counter; if (verbose) { printf("cloud_counter, boundary_counter = %d, %d\n", cloud_counter, boundary_counter); printf("Revised percent of cloud = %f\n", revised_ptm); } /* cloud covers more than 90% of the scene => no match => rest are definite shadows */ if (ptm <= 0.1 || revised_ptm >= 0.90) { for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { /* No Shadow Match due to too much cloud (>90 percent) */ if (cloud_mask[row][col] == 1) cloud_cal[row][col] = 1; else shadow_cal[row][col] = 1; } } } else { if (verbose) printf("Shadow Match in processing\n"); /* define constants */ float t_similar=0.30; float t_buffer=0.95; /* threshold for matching buffering */ int num_cldoj=9; /* minimum matched cloud object (pixels) */ int num_pix=8; /* number of inward pixes (240m) for cloud base temperature */ float a, b, c, omiga_par, omiga_per; if (verbose) { printf("Set cloud similarity = %.3f\n", t_similar); printf("Set matching buffer = %.3f\n", t_buffer); printf("Shadow match for cloud object >= %d pixels\n", num_cldoj); } int i_step; i_step=rint(2.0*(float)sub_size*tan(sun_ele_rad)); /* move 2 pixel at a time */ /* Get moving direction, the idea is to get the corner rows/cols */ int x_ul = 0; int y_ul = 0; int x_lr = 0; int y_lr = 0; int x_ll = 0; int y_ll = 0; int x_ur = 0; int y_ur = 0; for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { if (boundary_test[row][col] == 1) { y_ul = row; x_ul = col; goto next1; } } } next1: for (col = ncols - 1; col >= 0; col--) { for (row = 0; row < nrows; row++) { if (boundary_test[row][col] == 1) { y_ur = row; x_ur = col; goto next2; } } } next2: for (col = 0; col < ncols; col++) { for (row = nrows - 1; row >= 0; row--) { if (boundary_test[row][col] == 1) { y_ll = row; x_ll = col; goto next3; } } } next3: for (row = nrows - 1; row >= 0; row--) { for (col = ncols - 1; col >= 0; col--) { if (boundary_test[row][col] == 1) { y_lr = row; x_lr = col; goto next4; } } } next4: /* get view angle geometry */ viewgeo(x_ul,y_ul,x_ur,y_ur,x_ll,y_ll,x_lr,y_lr, &a, &b, &c, &omiga_par, &omiga_per); /* Allocate memory for segment cloud portion */ int *obj_num; obj_num = (int *)calloc(MAX_CLOUD_TYPE, sizeof(int)); cloud_node **cloud; cloud = (cloud_node **)ias_misc_allocate_2d_array(nrows, ncols, sizeof(cloud_node)); int **cloud_first_node; cloud_first_node = (int **)ias_misc_allocate_2d_array(2, MAX_CLOUD_TYPE, sizeof(int)); if (obj_num == NULL || cloud == NULL || cloud_first_node == NULL) { sprintf (errstr, "Allocating memory"); ERROR (errstr, "cloud/shadow match"); return -1; } /* Initialize the cloud nodes */ for (row = 0; row < nrows; row++) { for (col = 0; col <ncols; col++) { cloud[row][col].value = 0; cloud[row][col].row = 0; cloud[row][col].col = 0; cloud[row][col].parent = &cloud[row][col]; cloud[row][col].child = &cloud[row][col]; } } /* Labeling the cloud pixels */ label(cloud_mask, nrows, ncols, cloud, obj_num, cloud_first_node); /* The cloud pixels are not counted as cloud pixels if the total number of cloud pixels is less than 9 within a cloud cluster */ int num; int counter = 0; for (num = 1; num <= num_clouds; num++) { if (obj_num[num] <= MIN_CLOUD_OBJ) obj_num[num] = 0; else counter++; } if (verbose) printf("Num of real clouds = %d\n", counter); /* Cloud_cal pixels are cloud_mask pixels with < 9 pixels removed */ for (row = 0; row < nrows; row++) { for (col = 0; col <ncols; col++) { if ((cloud_mask[row][col] == 1) && (boundary_test[row][col] != 0) && (obj_num[cloud[row][col].value] != 0)) cloud_cal[row][col] = cloud_mask[row][col]; else cloud_cal[row][col] = 0; } } /* Need to read out whole image brightness temperature for band 6 */ int16 **temp; temp = (int16 **)ias_misc_allocate_2d_array(input->size.l, input->size.s, sizeof(int16)); if (!temp) { sprintf (errstr, "Allocating temp memory"); ERROR (errstr, "cloud/shadow match"); } /* Read out thermal band in 2d */ for (row = 0; row < nrows; row++) { if (!GetInputThermLine(input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); ERROR (errstr,"cloud/shadow match"); } memcpy(&temp[row][0], &input->therm_buf[0], input->size.s * sizeof(int16)); } /* Use iteration to get the optimal move distance, Calulate the moving cloud shadow */ int cloud_type; int **xy_type; int **tmp_xy_type; float **tmp_xys; int **orin_xys; int16 *temp_obj; int16 temp_obj_max = 0; int16 temp_obj_min = 0; int index; float r_obj; float pct_obj; float t_obj; float rate_elapse=6.5; float rate_dlapse=9.8; int max_cl_height; /* Max cloud base height (m) */ int min_cl_height; /* Min cloud base height (m) */ int max_height; int min_height; float record_thresh; float *record_h; int base_h; float *h; float i_xy; int out_all; int match_all; int total_all; float thresh_match; int i; for (cloud_type = 1; cloud_type <= num_clouds; cloud_type++) { if (obj_num[cloud_type] == 0) continue; else { /* Note: matlab array index starts with 1 and C starts with 0, array(3,1) in matlab is equal to array[2][0] in C */ min_cl_height = 200; max_cl_height = 12000; xy_type = (int **)ias_misc_allocate_2d_array(2, obj_num[cloud_type], sizeof(int)); tmp_xy_type = (int **)ias_misc_allocate_2d_array(2, obj_num[cloud_type], sizeof(int)); /* corrected for view angle xys */ tmp_xys = (float **)ias_misc_allocate_2d_array(2, obj_num[cloud_type], sizeof(float)); /* record the original xys */ orin_xys = (int **)ias_misc_allocate_2d_array(2, obj_num[cloud_type], sizeof(int)); if (xy_type == NULL || tmp_xy_type == NULL || tmp_xys == NULL || orin_xys == NULL) { sprintf (errstr, "Allocating cloud memory"); ERROR (errstr, "cloud/shadow match"); } /* Temperature of the cloud object */ temp_obj = malloc(obj_num[cloud_type] * sizeof(int16)); if (temp_obj == NULL) { sprintf (errstr, "Allocating temp_obj memory"); ERROR (errstr, "cloud/shadow match"); } temp_obj_max = 0; temp_obj_min = 0; index = 0; cloud_node *node; node = &cloud[cloud_first_node[0][cloud_type]] [cloud_first_node[1][cloud_type]]; while (node->child != node) { temp_obj[index] = temp[node->row][node->col]; if (temp_obj[index] > temp_obj_max) temp_obj_max = temp_obj[index]; if (temp_obj[index] < temp_obj_min) temp_obj_min = temp_obj[index]; orin_xys[0][index] = node->col; orin_xys[1][index] = node->row; index++; node = node->child; } temp_obj[index] = temp[node->row][node->col]; if (temp_obj[index] > temp_obj_max) temp_obj_max = temp_obj[index]; if (temp_obj[index] < temp_obj_min) temp_obj_min = temp_obj[index]; orin_xys[0][index] = node->col; orin_xys[1][index] = node->row; index++; obj_num[cloud_type] = index; /* the base temperature for cloud assume object is round r_obj is radium of object */ r_obj=sqrt((float)obj_num[cloud_type]/PI); /* number of inward pixes for correct temperature */ pct_obj=((r_obj-(float)num_pix)*(r_obj-(float)num_pix)) / (r_obj * r_obj); if ((pct_obj-1.0) >= MINSIGMA) pct_obj = 1.0;/* pct of edge pixel should be less than 1 */ prctile(temp_obj, obj_num[cloud_type],temp_obj_min, temp_obj_max, 100.0 * pct_obj, &t_obj); /* refine cloud height range (m) */ min_height = (int)rint(10.0*(t_templ-t_obj)/rate_dlapse); max_height = (int)rint(10.0*(t_temph-t_obj)); if (min_cl_height < min_height) min_cl_height = min_height; if (max_cl_height > max_height) max_cl_height = max_height; /* put the edge of the cloud the same value as t_obj */ for (i = 0; i < obj_num[cloud_type]; i++) { if (temp_obj[i] >rint(t_obj)) temp_obj[i]=rint(t_obj); } /* Allocate memory for h and record_h*/ h = malloc(obj_num[cloud_type] * sizeof(float)); record_h = calloc(obj_num[cloud_type], sizeof(float)); if (h == NULL || record_h == NULL) { sprintf (errstr, "Allocating h memory"); ERROR (errstr, "cloud/shadow match"); } /* initialize height and similarity info */ record_thresh=0.0; for (base_h = min_cl_height; base_h <= max_cl_height; base_h+=i_step) { for (i = 0; i < obj_num[cloud_type]; i++) { h[i]=(10.0*(t_obj-(float)temp_obj[i])) / rate_elapse+(float)base_h; } /* Get the true postion of the cloud calculate cloud DEM with initial base height */ mat_truecloud(orin_xys[0], orin_xys[1], obj_num[cloud_type], h, a, b, c, omiga_par, omiga_per, tmp_xys[0], tmp_xys[1]); out_all = 0; match_all = 0; total_all = 0; for (i = 0; i < obj_num[cloud_type]; i++) { i_xy=h[i]/((float)sub_size*tan(sun_ele_rad)); if ((input->meta.sun_az - 180.0) < MINSIGMA) { xy_type[1][i] = rint(tmp_xys[0][i]-i_xy*cos(sun_tazi_rad)); xy_type[0][i] = rint(tmp_xys[1][i]-i_xy*sin(sun_tazi_rad)); } else { xy_type[1][i] = rint(tmp_xys[0][i]+i_xy*cos(sun_tazi_rad)); xy_type[0][i] = rint(tmp_xys[1][i]+i_xy*sin(sun_tazi_rad)); } /* the id that is out of the image */ if (xy_type[0][i] < 0 || xy_type[0][i] >= nrows || xy_type[1][i] < 0 || xy_type[1][i] >= ncols) out_all++; else { if (boundary_test[xy_type[0][i]][xy_type[1][i]] == 0 || (cloud[xy_type[0][i]][xy_type[1][i]].value != cloud_type && (cloud_mask[xy_type[0][i]][xy_type[1][i]]>0 || shadow_mask[xy_type[0][i]][xy_type[1][i]] == 1))) match_all++; if (cloud[xy_type[0][i]][xy_type[1][i]].value != cloud_type) total_all++; } } match_all += out_all; total_all+=out_all; thresh_match=(float)match_all/(float)total_all; if (((thresh_match - t_buffer*record_thresh) >= MINSIGMA) && (base_h < max_cl_height-i_step) && ((record_thresh - 0.95)<MINSIGMA)) { if ((thresh_match - record_thresh) > MINSIGMA) { record_thresh=thresh_match; for (i = 0; i < obj_num[cloud_type]; i++) record_h[i] = h[i]; } } else if ((record_thresh - t_similar) > MINSIGMA) { float i_vir; for (i = 0; i < obj_num[cloud_type]; i++) { i_vir = record_h[i] / ((float)sub_size*tan(sun_ele_rad)); if ((input->meta.sun_az - 180.0) < MINSIGMA) { tmp_xy_type[1][i]=rint(tmp_xys[0][i]- i_vir*cos(sun_tazi_rad)); tmp_xy_type[0][i]=rint(tmp_xys[1][i]- i_vir*sin(sun_tazi_rad)); } else { tmp_xy_type[1][i]=rint(tmp_xys[0][i]+ i_vir*cos(sun_tazi_rad)); tmp_xy_type[0][i]=rint(tmp_xys[1][i]+ i_vir*sin(sun_tazi_rad)); } /* put data within range */ if (tmp_xy_type[0][i]<0) tmp_xy_type[0][i]=0; if (tmp_xy_type[0][i]>=nrows) tmp_xy_type[0][i]=nrows-1; if (tmp_xy_type[1][i]<0) tmp_xy_type[1][i]=0; if (tmp_xy_type[1][i]>=ncols) tmp_xy_type[1][i]=ncols-1; shadow_cal[tmp_xy_type[0][i]][tmp_xy_type[1][i]] = 1; } break; } else { record_thresh=0.0; continue; } } free(h); free(record_h); /* Free all the memory */ status = ias_misc_free_2d_array((void **)xy_type); status = ias_misc_free_2d_array((void **)tmp_xys); status = ias_misc_free_2d_array((void **)orin_xys); free(temp_obj); } } free(obj_num); status = ias_misc_free_2d_array((void **)temp); status = ias_misc_free_2d_array((void **)cloud); IplImage* src = cvCreateImage(cvSize(ncols, nrows), IPL_DEPTH_8U, 1); IplImage* dst = cvCreateImage(cvSize(ncols, nrows), IPL_DEPTH_8U, 1); if (!src || !dst) { sprintf (errstr, "Creating images\n"); ERROR (errstr, "cloud/shadow match"); } int dilation_type = 1; IplConvKernel* element = cvCreateStructuringElementEx( 2*cldpix + 1, 2*cldpix + 1, cldpix, cldpix, dilation_type, 0); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { src->imageData[row*ncols+col] = cloud_cal[row][col]; } } cvDilate(src, dst, element, 1); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { cloud_cal[row][col] = dst->imageData[row*ncols+col]; } } element = cvCreateStructuringElementEx( 2*sdpix + 1, 2*sdpix + 1, sdpix, sdpix, dilation_type, 0); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { src->imageData[row*ncols+col] = shadow_cal[row][col]; } } cvDilate(src, dst, element, 1); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { shadow_cal[row][col] = dst->imageData[row*ncols+col]; } } for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { src->imageData[row*ncols+col] = snow_mask[row][col]; } } cvDilate(src, dst, element, 1); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { snow_mask[row][col] = dst->imageData[row*ncols+col]; } } /* Release image memory */ cvReleaseImage(&src); cvReleaseImage(&dst); } /* Use cloud mask as the final output mask */ int cloud_count = 0; int shadow_count = 0; for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { if (boundary_test[row][col] ==0) final_mask[row][col] = 255; else if (cloud_cal[row][col] == 1) { final_mask[row][col] = 4; cloud_count++; } else if (shadow_cal[row][col] == 1) { final_mask[row][col] = 2; shadow_count++; } else if (snow_mask[row][col] == 1) final_mask[row][col] = 3; else if (water_mask[row][col] == 1) final_mask[row][col] = 1; else final_mask[row][col] = 0; } } /* Release the memory */ status = ias_misc_free_2d_array((void **)cloud_cal); status = ias_misc_free_2d_array((void **)shadow_cal); status = ias_misc_free_2d_array(( void **)boundary_test); if (verbose) { printf("cloud_count, shadow_count, boundary_counter = %d,%d,%d\n", cloud_count, shadow_count, boundary_counter); /* record cloud and cloud shadow percent; */ float cloud_shadow_percent; cloud_shadow_percent = (float)(cloud_count + shadow_count) / (float)boundary_counter; printf("The cloud and shadow percentage is %f\n", cloud_shadow_percent); } return 0; }
/****************************************************************************** MODULE: potential_cloud_shadow_snow_mask PURPOSE: Identify the cloud pixels, snow pixels, water pixels, clear land pixels, and potential shadow pixels RETURN: SUCCESS FAILURE HISTORY: Date Programmer Reason -------- --------------- ------------------------------------- 3/15/2013 Song Guo Original Development NOTES: 1. Thermal buffer is expected to be in degrees Celsius with a factor applied of 100. Many values which compare to the thermal buffer in this code are hardcoded and assume degrees celsius * 100. ******************************************************************************/ int potential_cloud_shadow_snow_mask ( Input_t * input, /*I: input structure */ float cloud_prob_threshold, /*I: cloud probability threshold */ float *ptm, /*O: percent of clear-sky pixels */ float *t_templ, /*O: percentile of low background temp */ float *t_temph, /*O: percentile of high background temp */ unsigned char **pixel_mask, /*I/O: pixel mask */ bool verbose /*I: value to indicate if intermediate messages be printed */ ) { char errstr[MAX_STR_LEN]; /* error string */ int nrows = input->size.l; /* number of rows */ int ncols = input->size.s; /* number of columns */ int ib = 0; /* band index */ int row = 0; /* row index */ int col = 0; /* column index */ int mask_counter = 0; /* mask counter */ int clear_pixel_counter = 0; /* clear sky pixel counter */ int clear_land_pixel_counter = 0; /* clear land pixel counter */ float ndvi, ndsi; /* NDVI and NDSI values */ int16 *f_temp = NULL; /* clear land temperature */ int16 *f_wtemp = NULL; /* clear water temperature */ float visi_mean; /* mean of visible bands */ float whiteness = 0.0; /* whiteness value */ float hot; /* hot value for hot test */ float lndptm; /* clear land pixel percentage */ float l_pt; /* low percentile threshold */ float h_pt; /* high percentile threshold */ float t_wtemp; /* high percentile water temperature */ float **wfinal_prob = NULL; /* final water pixel probabilty value */ float **final_prob = NULL; /* final land pixel probability value */ float wtemp_prob; /* water temperature probability value */ int t_bright; /* brightness test value for water */ float brightness_prob; /* brightness probability value */ int t_buffer; /* temperature test buffer */ float temp_l; /* difference of low/high tempearture percentiles */ float temp_prob; /* temperature probability */ float vari_prob; /* probability from NDVI, NDSI, and whiteness */ float max_value; /* maximum value */ float *prob = NULL; /* probability value */ float *wprob = NULL; /* probability value */ float clr_mask = 0.0; /* clear sky pixel threshold */ float wclr_mask = 0.0; /* water pixel threshold */ int16 *nir = NULL; /* near infrared band (band 4) data */ int16 *swir = NULL; /* short wavelength infrared (band 5) data */ float backg_b4; /* background band 4 value */ float backg_b5; /* background band 5 value */ int16 shadow_prob; /* shadow probability */ int status; /* return value */ int satu_bv; /* sum of saturated bands 1, 2, 3 value */ unsigned char mask; /* mask used for 1 pixel */ /* Dynamic memory allocation */ unsigned char **clear_mask = NULL; clear_mask = (unsigned char **) allocate_2d_array (input->size.l, input->size.s, sizeof (unsigned char)); if (clear_mask == NULL) RETURN_ERROR ("Allocating mask memory", "pcloud", FAILURE); if (verbose) printf ("The first pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } for (col = 0; col < ncols; col++) { int ib; for (ib = 0; ib < BI_REFL_BAND_COUNT; ib++) { if (input->buf[ib][col] == input->meta.satu_value_ref[ib]) input->buf[ib][col] = input->meta.satu_value_max[ib]; } if (input->therm_buf[col] == input->meta.therm_satu_value_ref) input->therm_buf[col] = input->meta.therm_satu_value_max; /* process non-fill pixels only Due to a problem with the input LPGS data, the thermal band may have values less than -9999 after scaling so exclude those as well */ if (input->therm_buf[col] <= -9999 || input->buf[BI_BLUE][col] == -9999 || input->buf[BI_GREEN][col] == -9999 || input->buf[BI_RED][col] == -9999 || input->buf[BI_NIR][col] == -9999 || input->buf[BI_SWIR_1][col] == -9999 || input->buf[BI_SWIR_2][col] == -9999) { mask = 0; } else { mask = 1; mask_counter++; } if ((input->buf[BI_RED][col] + input->buf[BI_NIR][col]) != 0 && mask == 1) { ndvi = (float) (input->buf[BI_NIR][col] - input->buf[BI_RED][col]) / (float) (input->buf[BI_NIR][col] + input->buf[BI_RED][col]); } else ndvi = 0.01; if ((input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]) != 0 && mask == 1) { ndsi = (float) (input->buf[BI_GREEN][col] - input->buf[BI_SWIR_1][col]) / (float) (input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]); } else ndsi = 0.01; /* Basic cloud test, equation 1 */ if (((ndsi - 0.8) < MINSIGMA) && ((ndvi - 0.8) < MINSIGMA) && (input->buf[BI_SWIR_2][col] > 300) && (input->therm_buf[col] < 2700)) { pixel_mask[row][col] |= 1 << CLOUD_BIT; } else pixel_mask[row][col] &= ~(1 << CLOUD_BIT); /* It takes every snow pixels including snow pixel under thin clouds or icy clouds, equation 20 */ if (((ndsi - 0.15) > MINSIGMA) && (input->therm_buf[col] < 1000) && (input->buf[BI_NIR][col] > 1100) && (input->buf[BI_GREEN][col] > 1000)) { pixel_mask[row][col] |= 1 << SNOW_BIT; } else pixel_mask[row][col] &= ~(1 << SNOW_BIT); /* Zhe's water test (works over thin cloud), equation 5 */ if (((((ndvi - 0.01) < MINSIGMA) && (input->buf[BI_NIR][col] < 1100)) || (((ndvi - 0.1) < MINSIGMA) && (ndvi > MINSIGMA) && (input->buf[BI_NIR][col] < 500))) && (mask == 1)) { pixel_mask[row][col] |= 1 << WATER_BIT; } else pixel_mask[row][col] &= ~(1 << WATER_BIT); if (mask == 0) pixel_mask[row][col] |= 1 << FILL_BIT; /* visible bands flatness (sum(abs)/mean < 0.6 => brigt and dark cloud), equation 2 */ if ((pixel_mask[row][col] & (1 << CLOUD_BIT)) && mask == 1) { visi_mean = (float) (input->buf[BI_BLUE][col] + input->buf[BI_GREEN][col] + input->buf[BI_RED][col]) / 3.0; if (visi_mean != 0) { whiteness = ((fabs ((float) input->buf[BI_BLUE][col] - visi_mean) + fabs ((float) input->buf[BI_GREEN][col] - visi_mean) + fabs ((float) input->buf[BI_RED][col] - visi_mean))) / visi_mean; } else { /* Just put a large value to remove them from cloud pixel identification */ whiteness = 100.0; } } /* Update cloud_mask, if one visible band is saturated, whiteness = 0, due to data type conversion, pixel value difference of 1 is possible */ if ((input->buf[BI_BLUE][col] >= (input->meta.satu_value_max[BI_BLUE] - 1)) || (input->buf[BI_GREEN][col] >= (input->meta.satu_value_max[BI_GREEN] - 1)) || (input->buf[BI_RED][col] >= (input->meta.satu_value_max[BI_RED] - 1))) { whiteness = 0.0; satu_bv = 1; } else { satu_bv = 0; } if ((pixel_mask[row][col] & (1 << CLOUD_BIT)) && (whiteness - 0.7) < MINSIGMA) pixel_mask[row][col] |= 1 << CLOUD_BIT; else pixel_mask[row][col] &= ~(1 << CLOUD_BIT); /* Haze test, equation 3 */ hot = (float) input->buf[BI_BLUE][col] - 0.5 * (float) input->buf[BI_RED][col] - 800.0; if ((pixel_mask[row][col] & (1 << CLOUD_BIT)) && (hot > MINSIGMA || satu_bv == 1)) pixel_mask[row][col] |= 1 << CLOUD_BIT; else pixel_mask[row][col] &= ~(1 << CLOUD_BIT); /* Ratio 4/5 > 0.75 test, equation 4 */ if ((pixel_mask[row][col] & (1 << CLOUD_BIT)) && input->buf[BI_SWIR_1][col] != 0) { if ((float) input->buf[BI_NIR][col] / (float) (input->buf[BI_SWIR_1][col]) - 0.75 > MINSIGMA) pixel_mask[row][col] |= 1 << CLOUD_BIT; else pixel_mask[row][col] &= ~(1 << CLOUD_BIT); } else pixel_mask[row][col] &= ~(1 << CLOUD_BIT); /* Test whether use thermal band or not */ if ((!(pixel_mask[row][col] & (1 << CLOUD_BIT))) && mask == 1) { clear_mask[row][col] |= 1 << CLEAR_BIT; clear_pixel_counter++; } else clear_mask[row][col] &= ~(1 << CLEAR_BIT); if ((!(pixel_mask[row][col] & (1 << WATER_BIT))) && clear_mask[row][col] & (1 << CLEAR_BIT)) { clear_mask[row][col] |= 1 << CLEAR_LAND_BIT; clear_land_pixel_counter++; clear_mask[row][col] &= ~(1 << CLEAR_WATER_BIT); } else if ((pixel_mask[row][col] & (1 << WATER_BIT)) && clear_mask[row][col] & (1 << CLEAR_BIT)) { clear_mask[row][col] |= 1 << CLEAR_WATER_BIT; clear_mask[row][col] &= ~(1 << CLEAR_LAND_BIT); } else { clear_mask[row][col] &= ~(1 << CLEAR_WATER_BIT); clear_mask[row][col] &= ~(1 << CLEAR_LAND_BIT); } } } printf ("\n"); *ptm = 100. * ((float) clear_pixel_counter / (float) mask_counter); lndptm = 100. * ((float) clear_land_pixel_counter / (float) mask_counter); if (verbose) { printf ("clear_pixels, clear_land_pixels, mask_counter = %d,%d,%d\n", clear_pixel_counter, clear_land_pixel_counter, mask_counter); printf ("*ptm, lndptm=%f,%f\n", *ptm, lndptm); } if ((*ptm - 0.1) <= MINSIGMA) /* No thermal test is needed, all clouds */ { *t_templ = -1.0; *t_temph = -1.0; for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { /* All cloud */ if (!(pixel_mask[row][col] & (1 << CLOUD_BIT))) pixel_mask[row][col] |= 1 << SHADOW_BIT; else pixel_mask[row][col] &= ~(1 << SHADOW_BIT); } } } else { f_temp = malloc (input->size.l * input->size.s * sizeof (int16)); f_wtemp = malloc (input->size.l * input->size.s * sizeof (int16)); if (f_temp == NULL || f_wtemp == NULL) { sprintf (errstr, "Allocating temp memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The second pass\n"); int16 f_temp_max = SHRT_MIN; int16 f_temp_min = SHRT_MAX; int16 f_wtemp_max = SHRT_MIN; int16 f_wtemp_min = SHRT_MAX; int index = 0; int index2 = 0; /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For the thermal band, read the input thermal band */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } for (col = 0; col < ncols; col++) { if (input->therm_buf[col] == input->meta.therm_satu_value_ref) input->therm_buf[col] = input->meta.therm_satu_value_max; if ((lndptm - 0.1) >= MINSIGMA) { /* get clear land temperature */ if (clear_mask[row][col] & (1 << CLEAR_LAND_BIT)) { f_temp[index] = input->therm_buf[col]; if (f_temp_max < f_temp[index]) f_temp_max = f_temp[index]; if (f_temp_min > f_temp[index]) f_temp_min = f_temp[index]; index++; } } else { /* get clear water temperature */ if (clear_mask[row][col] & (1 << CLEAR_BIT)) { f_temp[index] = input->therm_buf[col]; if (f_temp_max < f_temp[index]) f_temp_max = f_temp[index]; if (f_temp_min > f_temp[index]) f_temp_min = f_temp[index]; index++; } } /* Equation 7 */ if (clear_mask[row][col] & (1 << CLEAR_WATER_BIT)) { f_wtemp[index2] = input->therm_buf[col]; if (f_wtemp[index2] > f_wtemp_max) f_wtemp_max = f_wtemp[index2]; if (f_wtemp[index2] < f_wtemp_min) f_wtemp_min = f_wtemp[index2]; index2++; } } } printf ("\n"); /* Set maximum and minimum values to zero if no clear land/water pixels */ if (f_temp_min == SHRT_MAX) f_temp_min = 0; if (f_temp_max == SHRT_MIN) f_temp_max = 0; if (f_wtemp_min == SHRT_MAX) f_wtemp_min = 0; if (f_wtemp_max == SHRT_MIN) f_wtemp_max = 0; /* Tempearture for snow test */ l_pt = 0.175; h_pt = 1.0 - l_pt; /* 0.175 percentile background temperature (low) */ status = prctile (f_temp, index, f_temp_min, f_temp_max, 100.0 * l_pt, t_templ); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* 0.825 percentile background temperature (high) */ status = prctile (f_temp, index, f_temp_min, f_temp_max, 100.0 * h_pt, t_temph); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = prctile (f_wtemp, index2, f_wtemp_min, f_wtemp_max, 100.0 * h_pt, &t_wtemp); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Temperature test */ t_buffer = 4 * 100; *t_templ -= (float) t_buffer; *t_temph += (float) t_buffer; temp_l = *t_temph - *t_templ; /* Relase f_temp memory */ free (f_wtemp); free (f_temp); f_wtemp = NULL; f_temp = NULL; wfinal_prob = (float **) allocate_2d_array (input->size.l, input->size.s, sizeof (float)); final_prob = (float **) allocate_2d_array (input->size.l, input->size.s, sizeof (float)); if (wfinal_prob == NULL || final_prob == NULL) { sprintf (errstr, "Allocating prob memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The third pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } /* For the thermal band, data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Loop through each line in the image */ for (col = 0; col < ncols; col++) { for (ib = 0; ib < BI_REFL_BAND_COUNT - 1; ib++) { if (input->buf[ib][col] == input->meta.satu_value_ref[ib]) input->buf[ib][col] = input->meta.satu_value_max[ib]; } if (input->therm_buf[col] == input->meta.therm_satu_value_ref) input->therm_buf[col] = input->meta.therm_satu_value_max; if (pixel_mask[row][col] & (1 << WATER_BIT)) { /* Get cloud prob over water */ /* Temperature test over water */ wtemp_prob = (t_wtemp - (float) input->therm_buf[col]) / 400.0; if (wtemp_prob < MINSIGMA) wtemp_prob = 0.0; /* Brightness test (over water) */ t_bright = 1100; brightness_prob = (float) input->buf[BI_SWIR_1][col] / (float) t_bright; if ((brightness_prob - 1.0) > MINSIGMA) brightness_prob = 1.0; if (brightness_prob < MINSIGMA) brightness_prob = 0.0; /*Final prob mask (water), cloud over water probability */ wfinal_prob[row][col] = 100.0 * wtemp_prob * brightness_prob; final_prob[row][col] = 0.0; } else { temp_prob = (*t_temph - (float) input->therm_buf[col]) / temp_l; /* Temperature can have prob > 1 */ if (temp_prob < MINSIGMA) temp_prob = 0.0; /* label the non-fill pixels Due to a problem with the input LPGS data, the thermal band may have values less than -9999 after scaling so exclude those as well */ if (input->therm_buf[col] <= -9999 || input->buf[BI_BLUE][col] == -9999 || input->buf[BI_GREEN][col] == -9999 || input->buf[BI_RED][col] == -9999 || input->buf[BI_NIR][col] == -9999 || input->buf[BI_SWIR_1][col] == -9999 || input->buf[BI_SWIR_2][col] == -9999) { mask = 0; } else mask = 1; if ((input->buf[BI_RED][col] + input->buf[BI_NIR][col]) != 0 && mask == 1) { ndvi = (float) (input->buf[BI_NIR][col] - input->buf[BI_RED][col]) / (float) (input->buf[BI_NIR][col] + input->buf[BI_RED][col]); } else ndvi = 0.01; if ((input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]) != 0 && mask == 1) { ndsi = (float) (input->buf[BI_GREEN][col] - input->buf[BI_SWIR_1][col]) / (float) (input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]); } else ndsi = 0.01; /* NDVI and NDSI should not be negative */ if (ndsi < MINSIGMA) ndsi = 0.0; if (ndvi < MINSIGMA) ndvi = 0.0; visi_mean = (input->buf[BI_BLUE][col] + input->buf[BI_GREEN][col] + input->buf[BI_RED][col]) / 3.0; if (visi_mean != 0) { whiteness = ((fabs ((float) input->buf[BI_BLUE][col] - visi_mean) + fabs ((float) input->buf[BI_GREEN][col] - visi_mean) + fabs ((float) input->buf[BI_RED][col] - visi_mean))) / visi_mean; } else whiteness = 0.0; /* If one visible band is saturated, whiteness = 0 */ if ((input->buf[BI_BLUE][col] >= (input->meta.satu_value_max[BI_BLUE] - 1)) || (input->buf[BI_GREEN][col] >= (input->meta.satu_value_max[BI_GREEN] - 1)) || (input->buf[BI_RED][col] >= (input->meta.satu_value_max[BI_RED] - 1))) { whiteness = 0.0; } /* Vari_prob=1-max(max(abs(NDSI),abs(NDVI)),whiteness); */ if ((ndsi - ndvi) > MINSIGMA) max_value = ndsi; else max_value = ndvi; if ((whiteness - max_value) > MINSIGMA) max_value = whiteness; vari_prob = 1.0 - max_value; /*Final prob mask (land) */ final_prob[row][col] = 100.0 * (temp_prob * vari_prob); wfinal_prob[row][col] = 0.0; } } } printf ("\n"); /* Allocate memory for prob */ prob = malloc (input->size.l * input->size.s * sizeof (float)); if (prob == NULL) { sprintf (errstr, "Allocating prob memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } float prob_max = 0.0; float prob_min = 0.0; int index3 = 0; for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { if (clear_mask[row][col] & (1 << CLEAR_LAND_BIT)) { prob[index3] = final_prob[row][col]; if ((prob[index3] - prob_max) > MINSIGMA) prob_max = prob[index3]; if ((prob_min - prob[index3]) > MINSIGMA) prob_min = prob[index3]; index3++; } } } /* Dynamic threshold for land */ if (index3 != 0) { status = prctile2 (prob, index3, prob_min, prob_max, 100.0 * h_pt, &clr_mask); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile2 routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } } else { clr_mask = 27.5; /* no clear land pixel, make clr_mask double of cloud_prob_threshold */ } clr_mask += cloud_prob_threshold; /* Relase memory for prob */ free (prob); prob = NULL; /* Allocate memory for wprob */ wprob = malloc (input->size.l * input->size.s * sizeof (float)); if (wprob == NULL) { sprintf (errstr, "Allocating wprob memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } float wprob_max = 0.0; float wprob_min = 0.0; int index4 = 0; for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { if (clear_mask[row][col] & (1 << CLEAR_WATER_BIT)) { wprob[index4] = wfinal_prob[row][col]; if ((wprob[index4] - wprob_max) > MINSIGMA) wprob_max = wprob[index4]; if ((wprob_min - wprob[index4]) > MINSIGMA) wprob_min = wprob[index4]; index4++; } } } /* Dynamic threshold for water */ if (index4 != 0) { status = prctile2 (wprob, index4, wprob_min, wprob_max, 100.0 * h_pt, &wclr_mask); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile2 routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } } else { wclr_mask = 27.5; /* no clear water pixel, make wclr_mask 27.5 */ } wclr_mask += cloud_prob_threshold; /* Relase memory for wprob */ free (wprob); wprob = NULL; if (verbose) { printf ("pcloud probability threshold (land) = %.2f\n", clr_mask); printf ("pcloud probability threshold (water) = %.2f\n", wclr_mask); printf ("The fourth pass\n"); } /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For the thermal band, data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } for (col = 0; col < ncols; col++) { if (input->therm_buf[col] == input->meta.therm_satu_value_ref) input->therm_buf[col] = input->meta.therm_satu_value_max; if (((pixel_mask[row][col] & (1 << CLOUD_BIT)) && final_prob[row][col] > clr_mask && (!(pixel_mask[row][col] & (1 << WATER_BIT)))) || ((pixel_mask[row][col] & (1 << CLOUD_BIT)) && wfinal_prob[row][col] > wclr_mask && (pixel_mask[row][col] & (1 << WATER_BIT))) || (input->therm_buf[col] < *t_templ + t_buffer - 3500)) pixel_mask[row][col] |= 1 << CLOUD_BIT; else pixel_mask[row][col] &= ~(1 << CLOUD_BIT); } } printf ("\n"); /* Free the memory */ status = free_2d_array ((void **) wfinal_prob); if (status != SUCCESS) { sprintf (errstr, "Freeing memory: wfinal_prob\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = free_2d_array ((void **) final_prob); if (status != SUCCESS) { sprintf (errstr, "Freeing memory: final_prob\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Band 4 &5 flood fill */ nir = calloc (input->size.l * input->size.s, sizeof (int16)); swir = calloc (input->size.l * input->size.s, sizeof (int16)); if (nir == NULL || swir == NULL) { sprintf (errstr, "Allocating nir and swir memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Open the intermediate file for writing */ FILE *fd1; FILE *fd2; fd1 = fopen ("b4.bin", "wb"); if (fd1 == NULL) { sprintf (errstr, "Opening file: b4.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } fd2 = fopen ("b5.bin", "wb"); if (fd2 == NULL) { sprintf (errstr, "Opening file: b5.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The fifth pass\n"); int16 nir_max = 0; int16 nir_min = 0; int16 swir_max = 0; int16 swir_min = 0; int idx = 0; int idx2 = 0; /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } for (col = 0; col < ncols; col++) { if (input->buf[BI_NIR][col] == input->meta.satu_value_ref[BI_NIR]) { input->buf[BI_NIR][col] = input->meta.satu_value_max[BI_NIR]; } if (input->buf[BI_SWIR_1][col] == input->meta.satu_value_ref[BI_SWIR_1]) { input->buf[BI_SWIR_1][col] = input->meta.satu_value_max[BI_SWIR_1]; } if (clear_mask[row][col] & (1 << CLEAR_LAND_BIT)) { nir[idx] = input->buf[BI_NIR][col]; if (nir[idx] > nir_max) nir_max = nir[idx]; if (nir[idx] < nir_min) nir_min = nir[idx]; idx++; } if (clear_mask[row][col] & (1 << CLEAR_LAND_BIT)) { swir[idx2] = input->buf[BI_SWIR_1][col]; if (swir[idx2] > swir_max) swir_max = swir[idx2]; if (swir[idx2] < swir_min) swir_min = swir[idx2]; idx2++; } } /* Write out the intermediate file */ status = fwrite (&input->buf[BI_NIR][0], sizeof (int16), input->size.s, fd1); if (status != input->size.s) { sprintf (errstr, "Writing file: b4.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = fwrite (&input->buf[BI_SWIR_1][0], sizeof (int16), input->size.s, fd2); if (status != input->size.s) { sprintf (errstr, "Writing file: b5.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } } printf ("\n"); /* Close the intermediate file */ status = fclose (fd1); if (status) { sprintf (errstr, "Closing file: b4.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = fclose (fd2); if (status) { sprintf (errstr, "Closing file: b5.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Estimating background (land) Band 4 Ref */ status = prctile (nir, idx + 1, nir_min, nir_max, 100.0 * l_pt, &backg_b4); if (status != SUCCESS) { sprintf (errstr, "Calling prctile function\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = prctile (swir, idx2 + 1, swir_min, swir_max, 100.0 * l_pt, &backg_b5); if (status != SUCCESS) { sprintf (errstr, "Calling prctile function\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Release the memory */ free (nir); free (swir); nir = NULL; swir = NULL; /* Write out the intermediate values */ fd1 = fopen ("b4_b5.txt", "w"); if (fd1 == NULL) { sprintf (errstr, "Opening file: b4_b5.txt\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Write out the intermediate file */ fprintf (fd1, "%f\n", backg_b4); fprintf (fd1, "%f\n", backg_b5); fprintf (fd1, "%d\n", input->size.l); fprintf (fd1, "%d\n", input->size.s); /* Close the intermediate file */ status = fclose (fd1); if (status) { sprintf (errstr, "Closing file: b4_b5.txt\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Call the fill minima routine to do image fill */ status = system ("run_fillminima.py"); if (status != SUCCESS) { sprintf (errstr, "Running run_fillminima.py routine\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Open the intermediate file for reading */ fd1 = fopen ("filled_b4.bin", "rb"); if (fd1 == NULL) { sprintf (errstr, "Opening file: filled_b4.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } fd2 = fopen ("filled_b5.bin", "rb"); if (fd2 == NULL) { sprintf (errstr, "Opening file: filled_b5.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* May need allocate two memory for new band 4 and 5 */ int16 *new_nir; int16 *new_swir; new_nir = (int16 *) malloc (input->size.s * sizeof (int16)); new_swir = (int16 *) malloc (input->size.s * sizeof (int16)); if (new_nir == NULL || new_swir == NULL) { sprintf (errstr, "Allocating new_nir/new_swir memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The sixth pass\n"); for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } /* For the thermal band, data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Read out the intermediate file */ fread (&new_nir[0], sizeof (int16), input->size.s, fd1); fread (&new_swir[0], sizeof (int16), input->size.s, fd2); for (col = 0; col < ncols; col++) { if (input->buf[BI_NIR][col] == input->meta.satu_value_ref[BI_NIR]) { input->buf[BI_NIR][col] = input->meta.satu_value_max[BI_NIR]; } if (input->buf[BI_SWIR_1][col] == input->meta.satu_value_ref[BI_SWIR_1]) { input->buf[BI_SWIR_1][col] = input->meta.satu_value_max[BI_SWIR_1]; } /* process non-fill pixels only Due to a problem with the input LPGS data, the thermal band may have values less than -9999 after scaling so exclude those as well */ if (input->therm_buf[col] <= -9999 || input->buf[BI_BLUE][col] == -9999 || input->buf[BI_GREEN][col] == -9999 || input->buf[BI_RED][col] == -9999 || input->buf[BI_NIR][col] == -9999 || input->buf[BI_SWIR_1][col] == -9999 || input->buf[BI_SWIR_2][col] == -9999) { mask = 0; } else mask = 1; if (mask == 1) { new_nir[col] -= input->buf[BI_NIR][col]; new_swir[col] -= input->buf[BI_SWIR_1][col]; if (new_nir[col] < new_swir[col]) shadow_prob = new_nir[col]; else shadow_prob = new_swir[col]; if (shadow_prob > 200) pixel_mask[row][col] |= 1 << SHADOW_BIT; else pixel_mask[row][col] &= ~(1 << SHADOW_BIT); } else { pixel_mask[row][col] |= 1 << FILL_BIT; pixel_mask[row][col] &= ~(1 << CLOUD_BIT); pixel_mask[row][col] &= ~(1 << SHADOW_BIT); pixel_mask[row][col] &= ~(1 << WATER_BIT); pixel_mask[row][col] &= ~(1 << SNOW_BIT); } /* refine Water mask (no confusion water/cloud) */ if ((pixel_mask[row][col] & (1 << WATER_BIT)) && (pixel_mask[row][col] & (1 << CLOUD_BIT))) pixel_mask[row][col] &= ~(1 << WATER_BIT); } } printf ("\n"); /* Release the memory */ free (new_nir); free (new_swir); new_nir = NULL; new_swir = NULL; /* Close the intermediate file */ status = fclose (fd1); if (status) { sprintf (errstr, "Closing file: filled_b4.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = fclose (fd2); if (status) { sprintf (errstr, "Closing file: filled_b5.bin\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Remove the intermediate files */ status = system ("rm b4_b5.txt"); if (status != SUCCESS) { sprintf (errstr, "Removing b4_b5.txt file\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = system ("rm b4.bin"); if (status != SUCCESS) { sprintf (errstr, "Removing b4.bin file\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = system ("rm b5.bin"); if (status != SUCCESS) { sprintf (errstr, "Removing b5.bin file\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = system ("rm filled_b4.bin"); if (status != SUCCESS) { sprintf (errstr, "Removing filled_b4.bin file\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = system ("rm filled_b5.bin"); if (status != SUCCESS) { sprintf (errstr, "Removing filled_b5.bin file\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } } status = free_2d_array ((void **) clear_mask); if (status != SUCCESS) { sprintf (errstr, "Freeing memory: clear_mask\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } return SUCCESS; }
bool potential_cloud_shadow_snow_mask ( Input_t *input, float cloud_prob_threshold, float *ptm, float *t_templ, float *t_temph, unsigned char **cloud_mask, unsigned char **shadow_mask, unsigned char **snow_mask, unsigned char **water_mask, unsigned char **final_mask ) { char errstr[MAX_STR_LEN]; int nrows = input->size.l; int ncols = input->size.s; int ib = 0; int row =0; int col = 0; int mask_counter = 0; int clear_pixel_counter = 0; int clear_land_pixel_counter = 0; float ndvi, ndsi; int16 *f_temp = NULL; int16 *f_wtemp = NULL; float visi_mean; float whiteness = 0; float hot; float lndptm; float l_pt; float h_pt; int mask; float t_wtemp; float **wfinal_prob; float **final_prob; float wtemp_prob; int t_bright; float brightness_prob; int t_buffer; float temp_l; float temp_prob; float vari_prob; float max_value; float *prob = NULL; float clr_mask; float wclr_mask; int16 *nir = NULL; int16 *swir = NULL; float backg_b4; float backg_b5; float shadow_prob; int status; /* Dynamic memory allocation */ unsigned char **clear_mask; unsigned char **clear_land_mask; clear_mask = (unsigned char **)ias_misc_allocate_2d_array(input->size.l, input->size.s, sizeof(unsigned char)); clear_land_mask = (unsigned char **)ias_misc_allocate_2d_array( input->size.l, input->size.s, sizeof(unsigned char)); if (clear_mask == NULL || clear_land_mask ==NULL) { sprintf (errstr, "Allocating mask memory"); ERROR (errstr, "pcloud"); } printf("The first pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { /* Print status on every 100 lines */ if (!(row%1000)) { printf ("Processing line %d\r",row); fflush (stdout); } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine(input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine(input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); ERROR (errstr, "pcloud"); } for (col = 0; col < ncols; col++) { if ((input->buf[2][col] + input->buf[3][col]) != 0) ndvi = (input->buf[3][col] - input->buf[2][col]) / (input->buf[3][col] + input->buf[2][col]); else ndvi = 0.01; if ((input->buf[1][col] + input->buf[4][col]) != 0) ndsi = (input->buf[1][col] - input->buf[4][col]) / (input->buf[1][col] + input->buf[4][col]); else ndsi = 0.01; /* process non-fill pixels only */ if (input->therm_buf[col] > -9999) { mask = 1; mask_counter++; } else mask = 0; /* Basic cloud test */ if ((ndsi < 0.8) && (ndvi < 0.8) && (input->buf[5][col] > 300) && (input->therm_buf[col] < 2700)) cloud_mask[row][col] = 1; else cloud_mask[row][col] = 0; /* It takes every snow pixels including snow pixel under thin clouds or icy clouds */ if ((ndsi > 0.15) && (input->therm_buf[col] < 380) && (input->buf[3][col] > 1100) && (input->buf[1][col] > 1000)) snow_mask[row][col] = 1; else snow_mask[row][col] = 0; /* Zhe's water test (works over thin cloud) */ if (((ndvi < 0.01) && (input->buf[3][col] < 1100)) || ((ndvi < 0.1) && (ndvi > 0.0) && (input->buf[3][col] < 500))) water_mask[row][col] = 1; else water_mask[row][col] = 0; if (mask == 0) water_mask[row][col] = 255; /* visible bands flatness (sum(abs)/mean < 0.6 => brigt and dark cloud) */ visi_mean = (input->buf[0][col] + input->buf[1][col] + input->buf[2][col]) / 3.0; whiteness = ((abs(input->buf[0][col] - visi_mean) + abs(input->buf[1][col] - visi_mean) + abs(input->buf[2][col] - visi_mean)))/ visi_mean; /* Update cloud_mask, if one visible band is saturated, whiteness = 0 */ if (input->buf[0][col] > input->meta.therm_satu_value_ref || input->buf[1][col] > input->meta.therm_satu_value_ref || input->buf[2][col] > input->meta.therm_satu_value_ref) whiteness = 0; if (cloud_mask[row][col] == 1 && whiteness < 0.7) cloud_mask[row][col] = 1; else cloud_mask[row][col] = 0; /* Haze test */ hot = input->buf[0][col] - 0.5 *input->buf[2][col] - 800; if (cloud_mask[row][col] == 1 && (hot > 0.0 || abs(whiteness) < MINSIGMA)) cloud_mask[row][col] = 1; else cloud_mask[row][col] = 0; /* Ratio 4/5 > 0.75 test */ if (cloud_mask[row][col] == 1 && (input->buf[3][col] / input->buf[4][col] > 0.75)) cloud_mask[row][col] = 1; else cloud_mask[row][col] = 0; /* Test whether use thermal band or not */ if (cloud_mask[row][col] == 0 && mask == 1) { clear_mask[row][col] = 1; clear_pixel_counter++; } else clear_mask[row][col] = 0; if (water_mask[row][col] != 1 && clear_mask[row][col] == 1) { clear_land_mask[row][col] = 1; clear_land_pixel_counter++; } else clear_land_mask[row][col] = 0; } } *ptm = 100. * ((float)clear_pixel_counter / (float)mask_counter); lndptm = 100. * ((float)clear_land_pixel_counter / (float)mask_counter); if (*ptm <= 0.1) majority_filter(cloud_mask, nrows, ncols); else { f_temp = malloc(input->size.l * input->size.s * sizeof(int16)); f_wtemp = malloc(input->size.l * input->size.s * sizeof(int16)); if (f_temp == NULL || f_wtemp == NULL) { sprintf (errstr, "Allocating temp memory"); ERROR (errstr, "pcloud"); } } printf("The second pass\n"); int16 f_temp_max = 0; int16 f_temp_min = 0; int16 f_wtemp_max = 0; int16 f_wtemp_min = 0; int index = 0; int index2 = 0; /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { /* Print status on every 100 lines */ if (!(row%1000)) { printf ("Processing line %d\r", row); fflush (stdout); } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine(input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine(input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); ERROR (errstr, "pcloud"); } for (col =0; col < ncols; col++) { if (*ptm <= 0.1) /* No thermal test, meaningless for snow detection */ { /* All cloud */ if (cloud_mask[row][col] != 1) shadow_mask[row][col] = 1; else shadow_mask[row][col] = 0; #if 0 /* Tempoarary outpouts */ if (water_mask[row][col] == 1) final_mask[row][col] = 1; if (shadow_mask[row][col] == 1) final_mask[row][col] = 2; if (cloud_mask[row][col] == 1) final_mask[row][col] = 4; if (input->therm_buf[col] = -9999) final_mask[row][col] = 255; #endif } else { if (lndptm >= 0.1) { /* get clear land temperature */ if (clear_land_mask[row][col] == 1 && input->therm_buf[col] != -9999) { f_temp[index] = input->therm_buf[col]; if (f_temp_max < f_temp[index]) f_temp_max = f_temp[index]; if (f_temp_min > f_temp[index]) f_temp_min = f_temp[index]; index++; } } else { /*get clear water temperature */ if (clear_mask[row][col] == 1 && input->therm_buf[col] != -9999) { f_temp[index] = input->therm_buf[col]; if (f_temp_max < f_temp[index]) f_temp_max = f_temp[index]; if (f_temp_min > f_temp[index]) f_temp_min = f_temp[index]; index++; } } if (water_mask[row][col] == 1 && input->therm_buf[col] <= 300 && input->therm_buf[col] != -9999) { f_wtemp[index2] = input->therm_buf[col]; if (f_wtemp[index2] > f_wtemp_max) f_wtemp_max = f_wtemp[index2]; if (f_wtemp[index2] < f_wtemp_max) f_wtemp_min = f_wtemp[index2]; index2++; } } } } printf("Clear sky pixel percentage in this scene = %.2f\n", *ptm); if (*ptm <= 0.1) { *t_templ = -1.0; *t_temph = -1.0; return 0; } else { /* Tempearture for snow test */ l_pt = 0.175; h_pt = 1 - l_pt; printf("====%d,%d,%d,%d\n",f_wtemp_max,f_wtemp_min,f_temp_max,f_temp_min); #if 0 prctile(f_wtemp, index2 + 1, 100*h_pt, &t_wtemp); /* 0.175 percentile background temperature (low) */ prctile(f_temp, index + 1, 100*l_pt, t_templ); /* 0.825 percentile background temperature (high) */ prctile (f_temp, index + 1, 100*h_pt, t_temph); #endif t_wtemp = h_pt * (float)(f_wtemp_max-f_wtemp_min) + (float)f_wtemp_min; *t_templ = l_pt * (float)(f_temp_max-f_temp_min) + (float)f_temp_min; *t_temph = h_pt * (float)(f_temp_max-f_temp_min) + (float)f_temp_min; int f_temp_length; int f_wtemp_length; f_temp_length = f_temp_max - f_temp_min + 1; f_wtemp_length = f_wtemp_max - f_wtemp_min + 1; #if 0 prctile(f_wtemp, index2 + 1, f_wtemp_length, 100*h_pt, &t_wtemp); /* 0.175 percentile background temperature (low) */ prctile(f_temp, index + 1, f_temp_length, 100*l_pt, t_templ); /* 0.825 percentile background temperature (high) */ prctile (f_temp, index + 1, f_temp_length, 100*h_pt, t_temph); #endif printf("index, index2 = %d,%d\n",index,index2); /* Temperature test */ t_buffer = 4*100; *t_templ -= t_buffer; *t_temph += t_buffer; temp_l=*t_temph-*t_templ; printf("t_wtemp,t_templ,t_temph = %f,%f,%f\n",t_wtemp,*t_templ,*t_temph); /* Relase f_temp memory */ free(f_wtemp); free(f_temp); wfinal_prob = (float **)ias_misc_allocate_2d_array(input->size.l, input->size.s, sizeof(float)); final_prob = (float **)ias_misc_allocate_2d_array(input->size.l, input->size.s, sizeof(float)); if (wfinal_prob == NULL || final_prob == NULL) { sprintf (errstr, "Allocating prob memory"); ERROR (errstr, "pcloud"); } printf("The third pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { /* Print status on every 100 lines */ if (!(row%1000)) { printf ("Processing line %d\r",row); fflush (stdout); } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine(input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine(input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); ERROR (errstr, "pcloud"); } for (col = 0; col <ncols; col++) { /* Get cloud prob over water */ /* Temperature test over water */ wtemp_prob = (t_wtemp - input->therm_buf[col]) / 400.0; /* Brightness test (over water) */ t_bright = 1100; brightness_prob = input->buf[4][col] / t_bright; if (brightness_prob > 1) brightness_prob = 1; /*Final prob mask (water), cloud over water probability */ wfinal_prob[row][col] =100 * wtemp_prob * brightness_prob; temp_prob=(*t_temph-input->therm_buf[col]) / temp_l; /* Temperature can have prob > 1 */ if (temp_prob < 0) temp_prob = 0; if ((input->buf[2][col] + input->buf[3][col]) != 0) ndvi = (input->buf[3][col] - input->buf[2][col]) / (input->buf[3][col] + input->buf[2][col]); else ndvi = 0.01; if ((input->buf[1][col] + input->buf[4][col]) != 0) ndsi = (input->buf[1][col] - input->buf[4][col]) / (input->buf[1][col] + input->buf[4][col]); else ndsi = 0.01; /* NDVI and NDSI should not be negative */ if (input->buf[2][col] >= input->meta.therm_satu_value_ref && ndsi < 0) ndsi = 0; if (input->buf[3][col] >= input->meta.therm_satu_value_ref && ndvi < 0) ndvi = 0; /* Vari_prob=1-max(max(abs(NDSI),abs(NDVI)),whiteness); */ if (abs(ndsi) > abs(ndvi)) max_value = abs(ndsi); else max_value = abs(ndvi); if (whiteness > max_value) max_value = whiteness; vari_prob = 1 - max_value; /*Final prob mask (land) */ final_prob[row][col] = 100 * (temp_prob * vari_prob); } } prob = malloc(input->size.l * input->size.s * sizeof(float)); if(prob == NULL) { sprintf (errstr, "Allocating prob memory"); ERROR (errstr, "pcloud"); } float prob_max = 0.0; float prob_min = 0.0; int index3 = 0; for (row = 0; row < nrows; row++) { for (col = 0; col <ncols; col++) { if (clear_land_mask[row][col] == 1); { prob[index3] = final_prob[row][col]; if ((prob[index3] - prob_max) > MINSIGMA) prob_max = prob[index3]; if ((prob_min - prob[index3]) > MINSIGMA) prob_min = prob[index3]; index3++; } } } /*Dynamic threshold for land */ // prctile2(prob, index3+1, 100*h_pt, &clr_mask); printf("index3,prob_max,prob_min =%d, %f, %f\n",index3,prob_max,prob_min); clr_mask = h_pt * (prob_max - prob_min) + prob_min; printf("clr_mask =%d, %f\n",index3,clr_mask); #if 0 prctile2(prob, index3+1, 100*h_pt, &clr_mask); printf("clr_mask = %f\n",clr_mask); #endif clr_mask += cloud_prob_threshold; printf("clr_mask = %f\n",clr_mask); /* Relase memory for prob */ free(prob); /* Fixed threshold for water */ wclr_mask = 50.0; printf("pcloud probability threshold (land) = %.2f\n", clr_mask); printf("The fourth pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { /* Print status on every 100 lines */ if (!(row%1000)) { printf ("Processing line %d\r",row); fflush (stdout); } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine(input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine(input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); ERROR (errstr, "pcloud"); } for (col =0; col < ncols; col++) { if ((cloud_mask[row][col] == 1 && final_prob[row][col] > clr_mask && water_mask[row][col] == 0) || (cloud_mask[row][col] == 1 && wfinal_prob[row][col] > wclr_mask && water_mask[row][col] == 1) || (final_prob[row][col] > 99 && water_mask[row][col] == 0) || (input->therm_buf[col] < *t_templ - 3500)) cloud_mask[row][col] = 1; } } /* Free the memory */ status = ias_misc_free_2d_array((void **)wfinal_prob); status = ias_misc_free_2d_array((void **)final_prob); /* Band 4 flood fill */ nir = malloc(input->size.l * input->size.s * sizeof(int16)); swir = malloc(input->size.l * input->size.s * sizeof(int16)); if (nir == NULL || swir == NULL) { sprintf(errstr, "Allocating nir and swir memory"); ERROR (errstr, "pcloud"); } int16 nir_max = 0; int16 swir_max = 0; index = 0; index2 = 0; for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { if (clear_land_mask[row][col] == 1) { nir[index] = input->buf[3][col]; if (nir[index] > nir_max) nir_max = nir[index]; index++; } if (clear_land_mask[row][col] == 1) { nir[index2] = input->buf[4][col]; if (swir[index2] > swir_max) swir_max = swir[index2]; index2++; } } } status = ias_misc_free_2d_array((void **)clear_mask); status = ias_misc_free_2d_array((void **)clear_land_mask); /* Improve cloud mask by majority filtering */ majority_filter(cloud_mask, nrows, ncols); /* Estimating background (land) Band 4 Ref */ backg_b4 = l_pt * nir_max; backg_b5 = h_pt * swir_max; /* Release the memory */ free(nir); free(swir); /* May need allocate two memory for new band 4 and 5 after imfill (flood filling), also may need read in whole scene of bands 4 and 5 for flood filling purpose */ int16 **new_nir; int16 **new_swir; new_nir = (int16 **)ias_misc_allocate_2d_array(input->size.l, input->size.s, sizeof(int16)); new_swir = (int16 **)ias_misc_allocate_2d_array(input->size.l, input->size.s, sizeof(int16)); if (wfinal_prob == NULL || final_prob == NULL) { sprintf (errstr, "Allocating prob memory"); ERROR (errstr, "pcloud"); } printf("The fifth pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { /* Print status on every 100 lines */ if (!(row%1000)) { printf ("Processing line %d\r",row); fflush (stdout); } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine(input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine(input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); ERROR (errstr, "pcloud"); } for (col = 0; col < ncols; col++) { if (input->therm_buf[col] == -9999) { new_nir[row][col] = backg_b4; new_swir[row][col] = backg_b5; } else { new_nir[row][col] = input->buf[3][col]; new_swir[row][col] = input->buf[4][col]; } } } /* TODO: Fill in regional minimum band 4 ref*/ IplImage* img = cvCreateImage(cvSize(ncols, nrows), IPL_DEPTH_8U, 1); if (!img) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } // cvSet2D(img, ncols, nrows, new_nir); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { img->imageData[row*ncols+col] = new_nir[row][col]; // cvSet2D(img, col, row, new_nir[row][col]); } } CvPoint seed_point = cvPoint(3,3); CvScalar color = CV_RGB(1,0,0); cvFloodFill(img, seed_point, color, cvScalarAll(5.0), cvScalarAll(5.0), NULL, 4, NULL ); // cvGet2D(img, ncols, nrows, new_nir); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { new_nir[row][col] = img->imageData[row*ncols+col]; // new_nir[row][col] = cvGet2D(img, col, row); } } /* Release image memory */ cvReleaseImage(&img); /* TODO: Fill in regional minimum band 5 ref*/ IplImage* img2 = cvCreateImage(cvSize(ncols, nrows), IPL_DEPTH_8U, 1); if (!img2) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } // cvSet2D(img, ncols, nrows, new_swir); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { img2->imageData[row*ncols+col] = new_swir[row][col]; // cvSet2D(img2, col, row, new_swir[row][col]); } } cvFloodFill(img2, seed_point, color, cvScalarAll(5.0), cvScalarAll(5.0), NULL, 4, NULL ); // cvGet2D(img, ncols, nrows, new_swir); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { new_swir[row][col] = img2->imageData[row*ncols+col]; // new_swir[row][col] = cvGet2D(img2, col, row); } } /* Release image memory */ cvReleaseImage(&img2); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { if (new_nir[row][col] < new_swir[row][col]) shadow_prob = new_nir[row][col]; else shadow_prob = new_swir[row][col]; if (shadow_prob > 200) shadow_mask[row][col] = 1; else shadow_mask[row][col] = 0; } } status = ias_misc_free_2d_array((void **)new_nir); status = ias_misc_free_2d_array((void **)new_swir); } printf("The sixth pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { /* Print status on every 100 lines */ if (!(row%1000)) { printf ("Processing line %d\r",row); fflush (stdout); } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine(input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); ERROR (errstr, "pcloud"); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine(input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); ERROR (errstr, "pcloud"); } for (col = 0; col < ncols; col++) { /* refine Water mask - Zhe's water mask (no confusion water/cloud) */ if (water_mask[row][col] == 1 && cloud_mask[row][col] == 0) water_mask[row][col] = 1; else water_mask[row][col] = 0; if (input->therm_buf[col]==-9999) { cloud_mask[row][col] = 255; shadow_mask[row][col] = 255; // final_mask[row][col] = 255; } #if 0 /* Temporary outputs */ if (water_mask[row][col] == 1) final_mask[row][col] = 1; if (snow_mask[row][col] == 1) final_mask[row][col] = 3; if (shadow_mask[row][col] == 1) final_mask[row][col] = 2; if (cloud_mask[row][col] == 1) final_mask[row][col] = 4; if ((water_mask[row][col] != 1) && (snow_mask[row][col] != 1) && (shadow_cal[row][col] != 1) && (cloud_cal[row][col] != 1) && boundary_test[row][col] != 255) final_mask[row][col] = 0; #endif } } printf("t_wtemp,t_templ,t_temph = %f,%f,%f\n",t_wtemp,*t_templ,*t_temph); return 0; }
/***************************************************************************** MODULE: potential_cloud_shadow_snow_mask PURPOSE: Identify the cloud pixels, snow pixels, water pixels, clear land pixels, and potential shadow pixels RETURN: SUCCESS FAILURE HISTORY: Date Programmer Reason -------- --------------- ------------------------------------- 3/15/2013 Song Guo Original Development NOTES: 1. Thermal buffer is expected to be in degrees Celsius with a factor applied of 100. Many values which compare to the thermal buffer in this code are hardcoded and assume degrees celsius * 100. *****************************************************************************/ int potential_cloud_shadow_snow_mask ( Input_t * input, /*I: input structure */ float cloud_prob_threshold, /*I: cloud probability threshold */ float *clear_ptm, /*O: percent of clear-sky pixels */ float *t_templ, /*O: percentile of low background temp */ float *t_temph, /*O: percentile of high background temp */ unsigned char *pixel_mask, /*I/O: pixel mask */ unsigned char *conf_mask, /*I/O: confidence mask */ bool verbose /*I: value to indicate if intermediate messages should be printed */ ) { char errstr[MAX_STR_LEN]; /* error string */ int nrows = input->size.l; /* number of rows */ int ncols = input->size.s; /* number of columns */ int ib = 0; /* band index */ int row = 0; /* row index */ int col = 0; /* column index */ int image_data_counter = 0; /* mask counter */ int clear_pixel_counter = 0; /* clear sky pixel counter */ int clear_land_pixel_counter = 0; /* clear land pixel counter */ int clear_water_pixel_counter = 0; /* clear water pixel counter */ float ndvi, ndsi; /* NDVI and NDSI values */ int16 *f_temp = NULL; /* clear land temperature */ int16 *f_wtemp = NULL; /* clear water temperature */ float visi_mean; /* mean of visible bands */ float whiteness = 0.0; /* whiteness value */ float hot; /* hot value for hot test */ float land_ptm; /* clear land pixel percentage */ float water_ptm; /* clear water pixel percentage */ unsigned char land_bit; /* Which clear bit to test all or just land */ unsigned char water_bit; /* Which clear bit to test all or just water */ float l_pt; /* low percentile threshold */ float h_pt; /* high percentile threshold */ float t_wtemp; /* high percentile water temperature */ float *wfinal_prob = NULL; /* final water pixel probabilty value */ float *final_prob = NULL; /* final land pixel probability value */ float wtemp_prob; /* water temperature probability value */ int t_bright; /* brightness test value for water */ float brightness_prob; /* brightness probability value */ int t_buffer; /* temperature test buffer */ float temp_l; /* difference of low/high tempearture percentiles */ float temp_prob; /* temperature probability */ float vari_prob; /* probability from NDVI, NDSI, and whiteness */ float max_value; /* maximum value */ float *prob = NULL; /* probability value */ float *wprob = NULL; /* probability value */ float clr_mask = 0.0; /* clear sky pixel threshold */ float wclr_mask = 0.0; /* water pixel threshold */ int data_size; /* Data size for memory allocation */ int16 *nir = NULL; /* near infrared band data */ int16 *swir1 = NULL; /* short wavelength infrared band data */ int16 *nir_data = NULL; /* Data to be filled */ int16 *swir1_data = NULL; /* Data to be filled */ int16 *filled_nir_data = NULL; /* Filled result */ int16 *filled_swir1_data = NULL; /* Filled result */ float nir_boundary; /* NIR boundary value / background value */ float swir1_boundary; /* SWIR1 boundary value / background value */ int16 shadow_prob; /* shadow probability */ int status; /* return value */ int satu_bv; /* sum of saturated bands 1, 2, 3 value */ int pixel_index; int pixel_count; pixel_count = nrows * ncols; /* Dynamic memory allocation */ unsigned char *clear_mask = NULL; clear_mask = calloc (pixel_count, sizeof (unsigned char)); if (clear_mask == NULL) { RETURN_ERROR ("Allocating mask memory", "pcloud", FAILURE); } if (verbose) printf ("The first pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } /* For the thermal band */ /* Read the input thermal band -- data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } for (col = 0; col < ncols; col++) { pixel_index = row * ncols + col; int ib; for (ib = 0; ib < BI_REFL_BAND_COUNT; ib++) { if (input->buf[ib][col] == input->meta.satu_value_ref[ib]) input->buf[ib][col] = input->meta.satu_value_max[ib]; } if (input->therm_buf[col] == input->meta.therm_satu_value_ref) input->therm_buf[col] = input->meta.therm_satu_value_max; /* process non-fill pixels only Due to a problem with the input LPGS data, the thermal band may have values less than FILL_PIXEL after scaling so exclude those as well */ if (input->therm_buf[col] <= FILL_PIXEL || input->buf[BI_BLUE][col] == FILL_PIXEL || input->buf[BI_GREEN][col] == FILL_PIXEL || input->buf[BI_RED][col] == FILL_PIXEL || input->buf[BI_NIR][col] == FILL_PIXEL || input->buf[BI_SWIR_1][col] == FILL_PIXEL || input->buf[BI_SWIR_2][col] == FILL_PIXEL) { pixel_mask[pixel_index] = CF_FILL_BIT; clear_mask[pixel_index] = CF_CLEAR_FILL_BIT; continue; } image_data_counter++; if ((input->buf[BI_RED][col] + input->buf[BI_NIR][col]) != 0) { ndvi = (float) (input->buf[BI_NIR][col] - input->buf[BI_RED][col]) / (float) (input->buf[BI_NIR][col] + input->buf[BI_RED][col]); } else ndvi = 0.01; if ((input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]) != 0) { ndsi = (float) (input->buf[BI_GREEN][col] - input->buf[BI_SWIR_1][col]) / (float) (input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]); } else ndsi = 0.01; /* Basic cloud test, equation 1 */ if (((ndsi - 0.8) < MINSIGMA) && ((ndvi - 0.8) < MINSIGMA) && (input->buf[BI_SWIR_2][col] > 300) && (input->therm_buf[col] < 2700)) { pixel_mask[pixel_index] |= CF_CLOUD_BIT; } else pixel_mask[pixel_index] &= ~CF_CLOUD_BIT; /* It takes every snow pixel including snow pixels under thin or icy clouds, equation 20 */ if (((ndsi - 0.15) > MINSIGMA) && (input->therm_buf[col] < 1000) && (input->buf[BI_NIR][col] > 1100) && (input->buf[BI_GREEN][col] > 1000)) { pixel_mask[pixel_index] |= CF_SNOW_BIT; } else pixel_mask[pixel_index] &= ~CF_SNOW_BIT; /* Zhe's water test (works over thin cloud), equation 5 */ if ((((ndvi - 0.01) < MINSIGMA) && (input->buf[BI_NIR][col] < 1100)) || (((ndvi - 0.1) < MINSIGMA) && (ndvi > MINSIGMA) && (input->buf[BI_NIR][col] < 500))) { pixel_mask[pixel_index] |= CF_WATER_BIT; } else pixel_mask[pixel_index] &= ~CF_WATER_BIT; /* visible bands flatness (sum(abs)/mean < 0.6 => bright and dark cloud), equation 2 */ if (pixel_mask[pixel_index] & CF_CLOUD_BIT) { visi_mean = (float) (input->buf[BI_BLUE][col] + input->buf[BI_GREEN][col] + input->buf[BI_RED][col]) / 3.0; if (visi_mean != 0) { whiteness = ((fabs ((float) input->buf[BI_BLUE][col] - visi_mean) + fabs ((float) input->buf[BI_GREEN][col] - visi_mean) + fabs ((float) input->buf[BI_RED][col] - visi_mean))) / visi_mean; } else { /* Just put a large value to remove them from cloud pixel identification */ whiteness = 100.0; } } /* Update cloud_mask, if one visible band is saturated, whiteness = 0, due to data type conversion, pixel value difference of 1 is possible */ if ((input->buf[BI_BLUE][col] >= (input->meta.satu_value_max[BI_BLUE] - 1)) || (input->buf[BI_GREEN][col] >= (input->meta.satu_value_max[BI_GREEN] - 1)) || (input->buf[BI_RED][col] >= (input->meta.satu_value_max[BI_RED] - 1))) { whiteness = 0.0; satu_bv = 1; } else { satu_bv = 0; } if ((pixel_mask[pixel_index] & CF_CLOUD_BIT) && (whiteness - 0.7) < MINSIGMA) { pixel_mask[pixel_index] |= CF_CLOUD_BIT; } else pixel_mask[pixel_index] &= ~CF_CLOUD_BIT; /* Haze test, equation 3 */ hot = (float) input->buf[BI_BLUE][col] - 0.5 * (float) input->buf[BI_RED][col] - 800.0; if ((pixel_mask[pixel_index] & CF_CLOUD_BIT) && (hot > MINSIGMA || satu_bv == 1)) pixel_mask[pixel_index] |= CF_CLOUD_BIT; else pixel_mask[pixel_index] &= ~CF_CLOUD_BIT; /* Ratio 4/5 > 0.75 test, equation 4 */ if ((pixel_mask[pixel_index] & CF_CLOUD_BIT) && input->buf[BI_SWIR_1][col] != 0) { if ((float) input->buf[BI_NIR][col] / (float) input->buf[BI_SWIR_1][col] - 0.75 > MINSIGMA) pixel_mask[pixel_index] |= CF_CLOUD_BIT; else pixel_mask[pixel_index] &= ~CF_CLOUD_BIT; } else pixel_mask[pixel_index] &= ~CF_CLOUD_BIT; /* Build counters for clear, clear land, and clear water */ if (pixel_mask[pixel_index] & CF_CLOUD_BIT) { /* It is cloud so make sure none of the bits are set */ clear_mask[pixel_index] = CF_CLEAR_NONE; } else { clear_mask[pixel_index] = CF_CLEAR_BIT; clear_pixel_counter++; if (pixel_mask[pixel_index] & CF_WATER_BIT) { /* Add the clear water bit */ clear_mask[pixel_index] |= CF_CLEAR_WATER_BIT; clear_water_pixel_counter++; } else { /* Add the clear land bit */ clear_mask[pixel_index] |= CF_CLEAR_LAND_BIT; clear_land_pixel_counter++; } } } } printf ("\n"); *clear_ptm = 100.0 * ((float) clear_pixel_counter / (float) image_data_counter); land_ptm = 100.0 * ((float) clear_land_pixel_counter / (float) image_data_counter); water_ptm = 100.0 * ((float) clear_water_pixel_counter / (float) image_data_counter); if (verbose) { printf ("(clear_pixels, clear_land_pixels, clear_water_pixels," " image_data_counter) = (%d, %d, %d, %d)\n", clear_pixel_counter, clear_land_pixel_counter, clear_water_pixel_counter, image_data_counter); printf ("(clear_ptm, land_ptm, water_ptm) = (%f, %f, %f)\n", *clear_ptm, land_ptm, water_ptm); } if ((*clear_ptm - 0.1) <= MINSIGMA) { /* No thermal test is needed, all clouds */ *t_templ = -1.0; *t_temph = -1.0; for (pixel_index = 0; pixel_index < pixel_count; pixel_index++) { /* All cloud */ if (!(pixel_mask[pixel_index] & CF_CLOUD_BIT)) pixel_mask[pixel_index] |= CF_SHADOW_BIT; else pixel_mask[pixel_index] &= ~CF_SHADOW_BIT; } } else { f_temp = calloc (pixel_count, sizeof (int16)); f_wtemp = calloc (pixel_count, sizeof (int16)); if (f_temp == NULL || f_wtemp == NULL) { sprintf (errstr, "Allocating temp memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The second pass\n"); /* Determine which bit to test for land */ if ((land_ptm - 0.1) >= MINSIGMA) { /* use clear land only */ land_bit = CF_CLEAR_LAND_BIT; } else { /* not enough clear land so use all clear pixels */ land_bit = CF_CLEAR_BIT; } /* Determine which bit to test for water */ if ((water_ptm - 0.1) >= MINSIGMA) { /* use clear water only */ water_bit = CF_CLEAR_WATER_BIT; } else { /* not enough clear water so use all clear pixels */ water_bit = CF_CLEAR_BIT; } int16 f_temp_max = SHRT_MIN; int16 f_temp_min = SHRT_MAX; int16 f_wtemp_max = SHRT_MIN; int16 f_wtemp_min = SHRT_MAX; int land_count = 0; int water_count = 0; /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For the thermal band, read the input thermal band */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } for (col = 0; col < ncols; col++) { pixel_index = row * ncols + col; if (clear_mask[pixel_index] & CF_CLEAR_FILL_BIT) continue; if (input->therm_buf[col] == input->meta.therm_satu_value_ref) input->therm_buf[col] = input->meta.therm_satu_value_max; /* get clear land temperature */ if (clear_mask[pixel_index] & land_bit) { f_temp[land_count] = input->therm_buf[col]; if (f_temp_max < f_temp[land_count]) f_temp_max = f_temp[land_count]; if (f_temp_min > f_temp[land_count]) f_temp_min = f_temp[land_count]; land_count++; } /* get clear water temperature */ if (clear_mask[pixel_index] & water_bit) { f_wtemp[water_count] = input->therm_buf[col]; if (f_wtemp_max < f_wtemp[water_count]) f_wtemp_max = f_wtemp[water_count]; if (f_wtemp_min > f_wtemp[water_count]) f_wtemp_min = f_wtemp[water_count]; water_count++; } } } printf ("\n"); /* Set maximum and minimum values to zero if no clear land/water pixels */ if (f_temp_min == SHRT_MAX) f_temp_min = 0; if (f_temp_max == SHRT_MIN) f_temp_max = 0; if (f_wtemp_min == SHRT_MAX) f_wtemp_min = 0; if (f_wtemp_max == SHRT_MIN) f_wtemp_max = 0; /* Tempearture for snow test */ l_pt = 0.175; h_pt = 1.0 - l_pt; /* 0.175 percentile background temperature (low) */ status = prctile (f_temp, land_count, f_temp_min, f_temp_max, 100.0 * l_pt, t_templ); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* 0.825 percentile background temperature (high) */ status = prctile (f_temp, land_count, f_temp_min, f_temp_max, 100.0 * h_pt, t_temph); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = prctile (f_wtemp, water_count, f_wtemp_min, f_wtemp_max, 100.0 * h_pt, &t_wtemp); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Temperature test */ t_buffer = 4 * 100; *t_templ -= (float) t_buffer; *t_temph += (float) t_buffer; temp_l = *t_temph - *t_templ; /* Release f_temp memory */ free (f_wtemp); f_wtemp = NULL; free (f_temp); f_temp = NULL; wfinal_prob = calloc (pixel_count, sizeof (float)); final_prob = calloc (pixel_count, sizeof (float)); if (wfinal_prob == NULL || final_prob == NULL) { sprintf (errstr, "Allocating prob memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The third pass\n"); /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } /* For the thermal band, data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Loop through each sample in the image */ for (col = 0; col < ncols; col++) { pixel_index = row * ncols + col; if (pixel_mask[pixel_index] & CF_FILL_BIT) continue; for (ib = 0; ib < BI_REFL_BAND_COUNT - 1; ib++) { if (input->buf[ib][col] == input->meta.satu_value_ref[ib]) input->buf[ib][col] = input->meta.satu_value_max[ib]; } if (input->therm_buf[col] == input->meta.therm_satu_value_ref) input->therm_buf[col] = input->meta.therm_satu_value_max; if (pixel_mask[pixel_index] & CF_WATER_BIT) { /* Get cloud prob over water */ /* Temperature test over water */ wtemp_prob = (t_wtemp - (float) input->therm_buf[col]) / 400.0; if (wtemp_prob < MINSIGMA) wtemp_prob = 0.0; /* Brightness test (over water) */ t_bright = 1100; brightness_prob = (float) input->buf[BI_SWIR_1][col] / (float) t_bright; if ((brightness_prob - 1.0) > MINSIGMA) brightness_prob = 1.0; if (brightness_prob < MINSIGMA) brightness_prob = 0.0; /*Final prob mask (water), cloud over water probability */ wfinal_prob[pixel_index] = 100.0 * wtemp_prob * brightness_prob; final_prob[pixel_index] = 0.0; } else { temp_prob = (*t_temph - (float) input->therm_buf[col]) / temp_l; /* Temperature can have prob > 1 */ if (temp_prob < MINSIGMA) temp_prob = 0.0; if ((input->buf[BI_RED][col] + input->buf[BI_NIR][col]) != 0) { ndvi = (float) (input->buf[BI_NIR][col] - input->buf[BI_RED][col]) / (float) (input->buf[BI_NIR][col] + input->buf[BI_RED][col]); } else ndvi = 0.01; if ((input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]) != 0) { ndsi = (float) (input->buf[BI_GREEN][col] - input->buf[BI_SWIR_1][col]) / (float) (input->buf[BI_GREEN][col] + input->buf[BI_SWIR_1][col]); } else ndsi = 0.01; /* NDVI and NDSI should not be negative */ if (ndsi < MINSIGMA) ndsi = 0.0; if (ndvi < MINSIGMA) ndvi = 0.0; visi_mean = (input->buf[BI_BLUE][col] + input->buf[BI_GREEN][col] + input->buf[BI_RED][col]) / 3.0; if (visi_mean != 0) { whiteness = ((fabs ((float) input->buf[BI_BLUE][col] - visi_mean) + fabs ((float) input->buf[BI_GREEN][col] - visi_mean) + fabs ((float) input->buf[BI_RED][col] - visi_mean))) / visi_mean; } else whiteness = 0.0; /* If one visible band is saturated, whiteness = 0 */ if ((input->buf[BI_BLUE][col] >= (input->meta.satu_value_max[BI_BLUE] - 1)) || (input->buf[BI_GREEN][col] >= (input->meta.satu_value_max[BI_GREEN] - 1)) || (input->buf[BI_RED][col] >= (input->meta.satu_value_max[BI_RED] - 1))) { whiteness = 0.0; } /* Vari_prob=1-max(max(abs(NDSI),abs(NDVI)),whiteness); */ if ((ndsi - ndvi) > MINSIGMA) max_value = ndsi; else max_value = ndvi; if ((whiteness - max_value) > MINSIGMA) max_value = whiteness; vari_prob = 1.0 - max_value; /*Final prob mask (land) */ final_prob[pixel_index] = 100.0 * (temp_prob * vari_prob); wfinal_prob[pixel_index] = 0.0; } } } printf ("\n"); /* Allocate memory for prob */ prob = malloc (pixel_count * sizeof (float)); if (prob == NULL) { sprintf (errstr, "Allocating prob memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } float prob_max = 0.0; float prob_min = 0.0; land_count = 0; for (pixel_index = 0; pixel_index < pixel_count; pixel_index++) { if (clear_mask[pixel_index] & CF_CLEAR_FILL_BIT) continue; if (clear_mask[pixel_index] & land_bit) { prob[land_count] = final_prob[pixel_index]; if ((prob[land_count] - prob_max) > MINSIGMA) prob_max = prob[land_count]; if ((prob_min - prob[land_count]) > MINSIGMA) prob_min = prob[land_count]; land_count++; } } /* Dynamic threshold for land */ status = prctile2 (prob, land_count, prob_min, prob_max, 100.0 * h_pt, &clr_mask); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile2 routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } clr_mask += cloud_prob_threshold; /* Release memory for prob */ free (prob); prob = NULL; /* Allocate memory for wprob */ wprob = malloc (pixel_count * sizeof (float)); if (wprob == NULL) { sprintf (errstr, "Allocating wprob memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } float wprob_max = 0.0; float wprob_min = 0.0; water_count = 0; for (pixel_index = 0; pixel_index < pixel_count; pixel_index++) { if (clear_mask[pixel_index] & CF_CLEAR_FILL_BIT) continue; if (clear_mask[pixel_index] & water_bit) { wprob[water_count] = wfinal_prob[pixel_index]; if ((wprob[water_count] - wprob_max) > MINSIGMA) wprob_max = wprob[water_count]; if ((wprob_min - wprob[water_count]) > MINSIGMA) wprob_min = wprob[water_count]; water_count++; } } /* Dynamic threshold for water */ status = prctile2 (wprob, water_count, wprob_min, wprob_max, 100.0 * h_pt, &wclr_mask); if (status != SUCCESS) { sprintf (errstr, "Error calling prctile2 routine"); RETURN_ERROR (errstr, "pcloud", FAILURE); } wclr_mask += cloud_prob_threshold; /* Release memory for wprob */ free (wprob); wprob = NULL; if (verbose) { printf ("pcloud probability threshold (land) = %.2f\n", clr_mask); printf ("pcloud probability threshold (water) = %.2f\n", wclr_mask); printf ("The fourth pass\n"); } /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For the thermal band, data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } for (col = 0; col < ncols; col++) { pixel_index = row * ncols + col; if (pixel_mask[pixel_index] & CF_FILL_BIT) continue; if (input->therm_buf[col] == input->meta.therm_satu_value_ref) { input->therm_buf[col] = input->meta.therm_satu_value_max; } if (((pixel_mask[pixel_index] & CF_CLOUD_BIT) && (final_prob[pixel_index] > clr_mask) && (!(pixel_mask[pixel_index] & CF_WATER_BIT))) || ((pixel_mask[pixel_index] & CF_CLOUD_BIT) && (wfinal_prob[pixel_index] > wclr_mask) && (pixel_mask[pixel_index] & CF_WATER_BIT)) || (input->therm_buf[col] < *t_templ + t_buffer - 3500)) { /* This test indicates a high confidence */ conf_mask[pixel_index] = CLOUD_CONFIDENCE_HIGH; /* Original code was only this if test and setting the cloud bit or not */ pixel_mask[pixel_index] |= CF_CLOUD_BIT; } else if (((pixel_mask[pixel_index] & CF_CLOUD_BIT) && (final_prob[pixel_index] > clr_mask-10.0) && (!(pixel_mask[pixel_index] & CF_WATER_BIT))) || ((pixel_mask[pixel_index] & CF_CLOUD_BIT) && (wfinal_prob[pixel_index] > wclr_mask-10.0) && (pixel_mask[pixel_index] & CF_WATER_BIT))) { /* This test indicates a medium confidence */ conf_mask[pixel_index] = CLOUD_CONFIDENCE_MED; /* Don't set the cloud bit per the original code */ pixel_mask[pixel_index] &= ~CF_CLOUD_BIT; } else { /* All remaining are a low confidence */ conf_mask[pixel_index] = CLOUD_CONFIDENCE_LOW; /* Don't set the cloud bit per the original code */ pixel_mask[pixel_index] &= ~CF_CLOUD_BIT; } } } printf ("\n"); /* Free the memory */ free (wfinal_prob); wfinal_prob = NULL; free (final_prob); final_prob = NULL; /* Band NIR & SWIR1 flood fill section */ data_size = input->size.l * input->size.s; nir = calloc (data_size, sizeof (int16)); swir1 = calloc (data_size, sizeof (int16)); if (nir == NULL || swir1 == NULL) { sprintf (errstr, "Allocating nir and swir1 memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The fifth pass\n"); nir_data = calloc (data_size, sizeof (int16)); swir1_data = calloc (data_size, sizeof (int16)); filled_nir_data = calloc (data_size, sizeof (int16)); filled_swir1_data = calloc (data_size, sizeof (int16)); if (nir_data == NULL || swir1_data == NULL || filled_nir_data == NULL || filled_swir1_data == NULL) { sprintf (errstr, "Allocating nir and swir1 memory"); RETURN_ERROR (errstr, "pcloud", FAILURE); } int16 nir_max = 0; int16 nir_min = 0; int16 swir1_max = 0; int16 swir1_min = 0; int nir_count = 0; int swir1_count = 0; /* Loop through each line in the image */ for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } for (col = 0; col < ncols; col++) { pixel_index = row * ncols + col; if (clear_mask[pixel_index] & CF_CLEAR_FILL_BIT) continue; if (input->buf[BI_NIR][col] == input->meta.satu_value_ref[BI_NIR]) { input->buf[BI_NIR][col] = input->meta.satu_value_max[BI_NIR]; } if (input->buf[BI_SWIR_1][col] == input->meta.satu_value_ref[BI_SWIR_1]) { input->buf[BI_SWIR_1][col] = input->meta.satu_value_max[BI_SWIR_1]; } if (clear_mask[pixel_index] & land_bit) { nir[nir_count] = input->buf[BI_NIR][col]; if (nir[nir_count] > nir_max) nir_max = nir[nir_count]; if (nir[nir_count] < nir_min) nir_min = nir[nir_count]; nir_count++; swir1[swir1_count] = input->buf[BI_SWIR_1][col]; if (swir1[swir1_count] > swir1_max) swir1_max = swir1[swir1_count]; if (swir1[swir1_count] < swir1_min) swir1_min = swir1[swir1_count]; swir1_count++; } } /* NIR */ memcpy(&nir_data[row * input->size.s], &input->buf[BI_NIR][0], input->size.s * sizeof (int16)); /* SWIR1 */ memcpy(&swir1_data[row * input->size.s], &input->buf[BI_SWIR_1][0], input->size.s * sizeof (int16)); } printf ("\n"); /* Estimating background (land) Band NIR Ref */ status = prctile (nir, nir_count, nir_min, nir_max, 100.0 * l_pt, &nir_boundary); if (status != SUCCESS) { sprintf (errstr, "Calling prctile function\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } status = prctile (swir1, swir1_count, swir1_min, swir1_max, 100.0 * l_pt, &swir1_boundary); if (status != SUCCESS) { sprintf (errstr, "Calling prctile function\n"); RETURN_ERROR (errstr, "pcloud", FAILURE); } /* Release the memory */ free (nir); free (swir1); nir = NULL; swir1 = NULL; /* Call the fill minima routine to do image fill */ /* Perform them in parallel if threading is enabled */ #ifdef _OPENMP #pragma omp parallel sections #endif { { if (fill_local_minima_in_image("NIR Band", nir_data, input->size.l, input->size.s, nir_boundary, filled_nir_data) != SUCCESS) { printf ("Error Running fill_local_minima_in_image on NIR band"); status = ERROR; } } #ifdef _OPENMP #pragma omp section #endif { if (fill_local_minima_in_image("SWIR1 Band", swir1_data, input->size.l, input->size.s, swir1_boundary, filled_swir1_data) != SUCCESS) { printf ("Error Running fill_local_minima_in_image on SWIR1 band"); status = ERROR; } } } /* Release the memory */ free(nir_data); free(swir1_data); nir_data = NULL; swir1_data = NULL; if (status == ERROR) { free(filled_nir_data); free(filled_swir1_data); sprintf (errstr, "Running fill_local_minima_in_image"); RETURN_ERROR (errstr, "pcloud", FAILURE); } if (verbose) printf ("The sixth pass\n"); int16 new_nir; int16 new_swir1; for (row = 0; row < nrows; row++) { if (verbose) { /* Print status on every 1000 lines */ if (!(row % 1000)) { printf ("Processing line %d\r", row); fflush (stdout); } } /* For each of the image bands */ for (ib = 0; ib < input->nband; ib++) { /* Read each input reflective band -- data is read into input->buf[ib] */ if (!GetInputLine (input, ib, row)) { sprintf (errstr, "Reading input image data for line %d, " "band %d", row, ib); RETURN_ERROR (errstr, "pcloud", FAILURE); } } /* For the thermal band, data is read into input->therm_buf */ if (!GetInputThermLine (input, row)) { sprintf (errstr, "Reading input thermal data for line %d", row); RETURN_ERROR (errstr, "pcloud", FAILURE); } for (col = 0; col < ncols; col++) { pixel_index = row * ncols + col; if (input->buf[BI_NIR][col] == input->meta.satu_value_ref[BI_NIR]) { input->buf[BI_NIR][col] = input->meta.satu_value_max[BI_NIR]; } if (input->buf[BI_SWIR_1][col] == input->meta.satu_value_ref[BI_SWIR_1]) { input->buf[BI_SWIR_1][col] = input->meta.satu_value_max[BI_SWIR_1]; } if (pixel_mask[pixel_index] & CF_FILL_BIT) { conf_mask[pixel_index] = CF_FILL_PIXEL; continue; } new_nir = filled_nir_data[pixel_index] - input->buf[BI_NIR][col]; new_swir1 = filled_swir1_data[pixel_index] - input->buf[BI_SWIR_1][col]; if (new_nir < new_swir1) shadow_prob = new_nir; else shadow_prob = new_swir1; if (shadow_prob > 200) pixel_mask[pixel_index] |= CF_SHADOW_BIT; else pixel_mask[pixel_index] &= ~CF_SHADOW_BIT; /* refine Water mask (no confusion water/cloud) */ if ((pixel_mask[pixel_index] & CF_WATER_BIT) && (pixel_mask[pixel_index] & CF_CLOUD_BIT)) { pixel_mask[pixel_index] &= ~CF_WATER_BIT; } } } printf ("\n"); /* Release the memory */ free(nir_data); nir_data = NULL; free(swir1_data); swir1_data = NULL; free(filled_nir_data); filled_nir_data = NULL; free(filled_swir1_data); filled_swir1_data = NULL; } free (clear_mask); clear_mask = NULL; return SUCCESS; }