/*************************** * * cips7.c * COMPOSITE FILE COMPRISING: * ed.c * skeleton.c * segment.c * segment2.c * ***************************\ /********************************************** * * file d:\cips\ed.c * * Functions: This file contains * erosion * dilation * mask_erosion * mask_dilation * interior_outline * exterior_outline * copy_3_x_3 * opening * closing * get_shape_options * * Purpose: * These functions perform the erosion, * dilation, outlining, opening and * closing operations. * * External Calls: * wtiff.c - round_off_image_size * create_file_if_needed * write_array_into_tiff_image * tiff.c - read_tiff_header * rtiff.c - read_tiff_image * numcvrt.c - get_integer * * Modifications: * 14 March 1993 - created * ************************************************/ #include "cips.h" short edmask1[3][3] = {{0, 1, 0}, {0, 1, 0}, {0, 1, 0}}; short edmask2[3][3] = {{0, 0, 0}, {1, 1, 1}, {0, 0, 0}}; short edmask3[3][3] = {{0, 1, 0}, {1, 1, 1}, {0, 1, 0}}; short edmask4[3][3] = {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}; /******************************************* * * mask_dilation(... * * This function performs the dilation * operation using the erosion-dilation * 3x3 masks given above. It works on * 0-value images. * *******************************************/ mask_dilation(in_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type) char in_name[], out_name[]; int il, ie, ll, le; short the_image[ROWS][COLS], out_image[ROWS][COLS], mask_type, value; { int a, b, count, i, j, k; short mask[3][3], max; /************************************** * * Copy the 3x3 erosion-dilation mask * specified by the mask_type. * ***************************************/ switch(mask_type){ case 1: copy_3_x_3(mask, edmask1); break; case 2: copy_3_x_3(mask, edmask2); break; case 3: copy_3_x_3(mask, edmask3); break; case 4: copy_3_x_3(mask, edmask4); break; default: printf("\nInvalid mask type, using mask 4"); copy_3_x_3(mask, edmask4); break; } create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); /*************************** * * Loop over image array * ****************************/ printf("\n"); for(i=1; i max) max = the_image[i+a][j+b]; } /* ends if mask == 1 */ } /* ends loop over b */ } /* ends loop over a */ out_image[i][j] = max; } /* ends loop over j */ } /* ends loop over i */ fix_edges(out_image, 3); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends mask_dilation */ /******************************************* * * mask_erosion(... * * This function performs the erosion * operation using the erosion-dilation * 3x3 masks given above. It works on * 0-value images. * *******************************************/ mask_erosion(in_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type) char in_name[], out_name[]; int il, ie, ll, le; short the_image[ROWS][COLS], out_image[ROWS][COLS], mask_type, value; { int a, b, count, i, j, k; short mask[3][3], min; /************************************** * * Copy the 3x3 erosion-dilation mask * specified by the mask_type. * ***************************************/ switch(mask_type){ case 1: copy_3_x_3(mask, edmask1); break; case 2: copy_3_x_3(mask, edmask2); break; case 3: copy_3_x_3(mask, edmask3); break; case 4: copy_3_x_3(mask, edmask4); break; default: printf("\nInvalid mask type, using mask 4"); copy_3_x_3(mask, edmask4); break; } create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); /*************************** * * Loop over image array * ****************************/ printf("\n"); for(i=1; i threshold) out_image[i][j] = 0; } /* ends if the_image == value */ } /* ends loop over j */ } /* ends loop over i */ fix_edges(out_image, 3); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends erosion */ /******************************************* * * dilation(... * * This function performs the dilation * operation. If a 0 pixel has more than * threshold number of value neighbors, * you dilate it by setting it to value. * *******************************************/ dilation(in_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold) char in_name[], out_name[]; int il, ie, ll, le; short the_image[ROWS][COLS], out_image[ROWS][COLS], threshold, value; { int a, b, count, i, j, k; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); /*************************** * * Loop over image array * ****************************/ printf("\n"); for(i=1; i threshold) out_image[i][j] = value; } /* ends if the_image == 0 */ } /* ends loop over j */ } /* ends loop over i */ fix_edges(out_image, 3); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends dilation */ /******************************************* * * interior_outline(... * * This function produces the outline of * any "holes" inside an object. The * method is: * output = erosion of input * final output = input - output * *******************************************/ interior_outline(in_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type) char in_name[], out_name[]; int il, ie, ll, le; short the_image[ROWS][COLS], out_image[ROWS][COLS], mask_type, value; { int a, b, count, i, j, k; short mask[3][3], max; /************************************** * * Copy the 3x3 erosion-dilation mask * specified by the mask_type. * ***************************************/ switch(mask_type){ case 1: copy_3_x_3(mask, edmask1); break; case 2: copy_3_x_3(mask, edmask2); break; case 3: copy_3_x_3(mask, edmask3); break; case 4: copy_3_x_3(mask, edmask4); break; default: printf("\nInvalid mask type, using mask 4"); copy_3_x_3(mask, edmask4); break; } create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); mask_erosion(in_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type); for(i=0; i 1){ count = 1; while(count < number){ count++; mask_erosion(out_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type); } /* ends while */ } /* ends if number > 1 */ mask_dilation(out_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends opening */ /******************************************* * * closing(... * * Closing is dilation followed by erosion. * This routine will use the mask erosion * and dilation. You could use the other * types and you could mix the two types. * * The number parameter specifies how * dilations to perform before doing one * erosion. * *******************************************/ closing(in_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type, number) char in_name[], out_name[]; int il, ie, ll, le, number; short the_image[ROWS][COLS], out_image[ROWS][COLS], mask_type, value; { int a, b, count, i, j, k; short mask[3][3], max; /************************************** * * Copy the 3x3 erosion-dilation mask * specified by the mask_type. * ***************************************/ switch(mask_type){ case 1: copy_3_x_3(mask, edmask1); break; case 2: copy_3_x_3(mask, edmask2); break; case 3: copy_3_x_3(mask, edmask3); break; case 4: copy_3_x_3(mask, edmask4); break; default: printf("\nInvalid mask type, using mask 4"); copy_3_x_3(mask, edmask4); break; } create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); mask_dilation(in_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type); if(number > 1){ count = 1; while(count < number){ count++; mask_dilation(out_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type); } /* ends while */ } /* ends if number > 1 */ mask_erosion(out_name, out_name, the_image, out_image, il, ie, ll, le, value, mask_type); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends closing */ /******************************************* * * get_shape_options(... * * This function interacts with the user * to obtain the parameters for calling * the shape routines. * *******************************************/ get_shape_options(type, value, threshold, number) char type[]; int *number, *threshold; short *value; { int not_finished = 1, response; while(not_finished){ printf("\nThe shape options are:"); printf("\n\t1. Type is %s", type); printf("\n\t recall: EROsion DILation Mask-ERosion" "\n\t Mask_DIlation INTerior-outline" "\n\t EXTerior-outline THInning" "\n\t Dilate-Not-Join OPEning" "\n\t CLOsing SPecial-Opening" "\n\t SPecial-Closing" "\n\t Euclidean-Distance-Measure" "\n\t Medial-Axis-Transform"); printf("\n\t2. value is %d", *value); printf("\n\t3. threshold or mask type is %d", *threshold); printf("\n\t4. number of iterations is %d", *number); printf("\n\t (used only in opening and closing)"); printf("\n\nEnter choice (0 = no change) _\b"); get_integer(&response); if(response == 0){ not_finished = 0; } if(response == 1){ printf("\nEnter type of operation"); printf("\n\t recall: EROsion DILation Mask-ERosion" "\n\t Mask_DIlation INTerior-outline" "\n\t EXTerior-outline THInning" "\n\t Dilate-Not-Join OPEning" "\n\t CLOsing SPecial-Opening" "\n\t SPecial-Closing" "\n\t Euclidean-Distance-Measure" "\n\t Medial-Axis-Transform"); printf("\n\t:"); gets(type); } if(response == 2){ printf("\nEnter value: ___\b\b\b"); get_integer(value); } if(response == 3){ printf("\nEnter threshold or mask type: ___"); printf("\b\b\b"); get_integer(threshold); } if(response == 4){ printf("\nEnter number of iterations: ___"); printf("\b\b\b"); get_integer(number); } } /* ends while not_finished */ } /* ends get_shape_options */ /********************************************** * * file d:\cips\skeleton.c * * Functions: This file contains * thinning * can_thin * dilate_not_join * can_dilate * little_label_and_check * special_closing * special_opening * edm * distanc_8 * mat * mat_d * * Purpose: * These functions thin objects in * an image, dilate objects, and * perform opening and closing * without removing or joining * objects. * * External Calls: * wtiff.c - round_off_image_size * create_file_if_needed * write_array_into_tiff_image * tiff.c - read_tiff_header * rtiff.c - read_tiff_image * numcvrt.c - get_integer * * * Modifications: * 7 March 1993 - created * ************************************************/ /******************************************* * * thinning(... * * Use a variation of the grass fire * wave front approach. * * Raster scan the image left to right * and examine and thin the left edge pixels * (a 0 to value transition). Process them * normally and "save" the result. Next, * raster scan the image right to left and * save. Raster scan top to bottom and save. * Raster scan bottom to top and save. * * That is one complete pass. * * Keep track of pixels thinned for a * pass and quit when you make a complete * pass without thinning any pixels. * *******************************************/ thinning(in_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold, once_only) char in_name[], out_name[]; int il, ie, ll, le, once_only; short the_image[ROWS][COLS], out_image[ROWS][COLS], threshold, value; { int a, b, big_count, count, i, j, k, not_finished; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); for(i=0; i threshold){ if(can_thin(the_image, i, j, value)){ out_image[i][j] = 0; big_count++; } /* ends if can_thin */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over j */ } /* ends loop over i */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i threshold){ if(can_thin(the_image, i, j, value)){ out_image[i][j] = 0; big_count++; } /* ends if can_thin */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over j */ } /* ends loop over i */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i threshold){ if(can_thin(the_image, i, j, value)){ out_image[i][j] = 0; big_count++; } /* ends if can_thin */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over i */ } /* ends loop over j */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i threshold){ if(can_thin(the_image, i, j, value)){ out_image[i][j] = 0; big_count++; } /* ends if can_thin */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over i */ } /* ends loop over j */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i= 0) && ((a+c) <= 2) && ((b+d) >= 0) && ((b+d) <= 2)){ if(temp[a+c][b+d] == value){ no_neighbor = 0; } /* ends if temp == value */ } /* ends if part of temp array */ } /* ends loop over d */ } /* ends loop over c */ temp[a][b] = value; /************************************** * * If the non-zero pixel did not * have any non-zero neighbors, * no_neighbor still equals 1, * and we cannot thin, so return * zero. * ***************************************/ if(no_neighbor){ return(zero); } } /* ends if temp[a][b] == value */ } /* ends loop over b */ } /* ends loop over a */ /************************************** * * First, ensure the object is more * than two wide. If it is two wide, * you will thin out the entire object. * Check in all eight directions. * If the distance to a zero is 0 or * >= 2, then ok you can thin so go * on to the remainder of this routine. * If not, you cannot thin so return * zero. * ***************************************/ return(one); } /* ends can_thin */ /******************************************* * * dilate_not_join(... * * Use a variation of the grass fire * wave front approach. * * Raster scan the image left to right * and examine and dilate the left edge pixels * (a value to 0 transition). Process them * normally and "save" the result. Next, * raster scan the image right to left and * save. Raster scan top to bottom and save. * Raster scan bottom to top and save. * * That is one complete pass. * *******************************************/ dilate_not_join(in_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold) char in_name[], out_name[]; int il, ie, ll, le; short the_image[ROWS][COLS], out_image[ROWS][COLS], threshold, value; { int a, b, count, i, j, k; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); for(i=0; i threshold){ if(can_dilate(the_image,i,j,value)){ out_image[i][j] = value; } /* ends if can_dilate */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over j */ } /* ends loop over i */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i threshold){ if(can_dilate(the_image,i,j,value)){ out_image[i][j] = value; } /* ends if can_dilate */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over j */ } /* ends loop over i */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i threshold){ if(can_dilate(the_image,i,j,value)){ out_image[i][j] = value; } /* ends if can_dilate */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over i */ } /* ends loop over j */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i threshold){ if(can_dilate(the_image,i,j,value)){ out_image[i][j] = value; } /* ends if can_dilate */ } /* ends if count > threshold */ } /* ends if the_image == value */ } /* ends loop over i */ } /* ends loop over j */ /************************************** * * Copy the output back to the input. * **************************************/ for(i=0; i= 0 && c <= 2 && d >= 0 && d <= 2) if(temp[c][d] == value){ /* PUSH */ *stack_pointer = *stack_pointer + 1; stack[*stack_pointer][0] = c; stack[*stack_pointer][1] = d; *stack_empty = 0; } /* ends if temp == value */ } /* ends loop over d */ } /* ends loop over c */ } /* ends little_label_and_check */ /******************************************* * * special_closing(... * * Closing is dilation followed by erosion. * This routine will use the dilate_not_join * dilation routine. This will not allow * two separate objects to join. * * The number parameter specifies how * dilations to perform before doing one * erosion. * *******************************************/ special_closing(in_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold, number) char in_name[], out_name[]; int il, ie, ll, le, number; short the_image[ROWS][COLS], out_image[ROWS][COLS], threshold, value; { int a, b, count, i, j, k; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); dilate_not_join(in_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold); if(number > 1){ count = 1; while(count < number){ count++; dilate_not_join(out_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold); } /* ends while */ } /* ends if number > 1 */ erosion(out_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends special_closing */ /******************************************* * * special_opening(... * * Opening is erosion followed by dilation. * This routine will use the thinning * erosion routine. This will not allow * an object to erode to nothing. * * The number parameter specifies how * erosions to perform before doing one * dilation. * *******************************************/ special_opening(in_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold, number) char in_name[], out_name[]; int il, ie, ll, le, number; short the_image[ROWS][COLS], out_image[ROWS][COLS], threshold, value; { int a, b, count, i, j, k; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); thinning(in_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold, 1); if(number > 1){ count = 1; while(count < number){ count++; thinning(out_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold, 1); } /* ends while */ } /* ends if number > 1 */ dilation(out_name, out_name, the_image, out_image, il, ie, ll, le, value, threshold); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends special_opening */ /******************************************* * * edm(.. * * This function calculates the Euclidean * distance measure for objects in an image. * It calculates the distance from any * pixel=value to the nearest zero pixel * *******************************************/ edm(in_name, out_name, the_image, out_image, il, ie, ll, le, value) char in_name[], out_name[]; int il, ie, ll, le; short the_image[ROWS][COLS], out_image[ROWS][COLS], value; { int a, b, count, i, j, k; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); for(i=0; i= 0){ if(the_image[i][j] == value) dist1++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ result = dist1; /* straight down */ measuring = 1; i = a; j = b; while(measuring){ i++; if(i <= ROWS-1){ if(the_image[i][j] == value) dist2++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ if(dist2 <= result) result = dist2; /* straight left */ measuring = 1; i = a; j = b; while(measuring){ j--; if(j >= 0){ if(the_image[i][j] == value) dist3++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ if(dist3 <= result) result = dist3; /* straight right */ measuring = 1; i = a; j = b; while(measuring){ j++; if(j <= COLS-1){ if(the_image[i][j] == value) dist4++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ if(dist4 <= result) result = dist4; /* left and up */ measuring = 1; i = a; j = b; while(measuring){ j--; i--; if(j >= 0 && i>=0){ if(the_image[i][j] == value) dist5++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist5 = (dist5*14)/10; if(dist5 <= result) result = dist5; /* right and up */ measuring = 1; i = a; j = b; while(measuring){ j++; i--; if(j <=COLS-1 && i>=0){ if(the_image[i][j] == value) dist6++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist6 = (dist6*14)/10; if(dist6 <= result) result = dist6; /* right and down */ measuring = 1; i = a; j = b; while(measuring){ j++; i++; if(j <=COLS-1 && i<=ROWS-1){ if(the_image[i][j] == value) dist7++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist7 = (dist7*14)/10; if(dist7 <= result) result = dist7; /* left and down */ measuring = 1; i = a; j = b; while(measuring){ j--; i++; if(j >=0 && i<=ROWS-1){ if(the_image[i][j] == value) dist8++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist8 = (dist8*14)/10; if(dist8 <= result) result = dist8; return(result); } /* ends distance_8 */ /******************************************* * * mat(.. * * This function finds the medial axis * transform for objects in an image. * The mat are those points that are * minimally distant to more than one * boundary point. * *******************************************/ mat(in_name, out_name, the_image, out_image, il, ie, ll, le, value) char in_name[], out_name[]; int il, ie, ll, le; short the_image[ROWS][COLS], out_image[ROWS][COLS], value; { int a, b, count, i, j, k, length, width; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); for(i=0; i= 0){ if(the_image[i][j] == value) dist1++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ result = dist1; min1 = dist1; /* straight down */ measuring = 1; i = a; j = b; while(measuring){ i++; if(i <= ROWS-1){ if(the_image[i][j] == value) dist2++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ if(dist2 <= result) result = dist2; if(dist2 < min1){ min2 = min1; min1 = dist2; } else if(dist2 < min2) min2 = dist2; /* straight left */ measuring = 1; i = a; j = b; while(measuring){ j--; if(j >= 0){ if(the_image[i][j] == value) dist3++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ if(dist3 <= result) result = dist3; if(dist3 < min1){ min2 = min1; min1 = dist3; } else if(dist3 < min2) min2 = dist3; /* straight right */ measuring = 1; i = a; j = b; while(measuring){ j++; if(j <= COLS-1){ if(the_image[i][j] == value) dist4++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ if(dist4 <= result) result = dist4; if(dist4 < min1){ min2 = min1; min1 = dist4; } else if(dist4 < min2) min2 = dist4; /* left and up */ measuring = 1; i = a; j = b; while(measuring){ j--; i--; if(j >= 0 && i>=0){ if(the_image[i][j] == value) dist5++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist5 = ((dist5*14)+7)/10; if(dist5 <= result) result = dist5; if(dist5 < min1){ min2 = min1; min1 = dist5; } else if(dist5 < min2) min2 = dist5; /* right and up */ measuring = 1; i = a; j = b; while(measuring){ j++; i--; if(j <=COLS-1 && i>=0){ if(the_image[i][j] == value) dist6++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist6 = ((dist6*14)+7)/10; if(dist6 <= result) result = dist6; if(dist6 < min1){ min2 = min1; min1 = dist6; } else if(dist6 < min2) min2 = dist6; /* right and down */ measuring = 1; i = a; j = b; while(measuring){ j++; i++; if(j <=COLS-1 && i<=ROWS-1){ if(the_image[i][j] == value) dist7++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist7 = ((dist7*14)+7)/10; if(dist7 <= result) result = dist7; if(dist7 < min1){ min2 = min1; min1 = dist7; } else if(dist7 < min2) min2 = dist7; /* left and down */ measuring = 1; i = a; j = b; while(measuring){ j--; i++; if(j >=0 && i<=ROWS-1){ if(the_image[i][j] == value) dist8++; else measuring = 0; } else measuring = 0; } /* ends while measuring */ dist8 = ((dist8*14)+7)/10; if(dist8 <= result) result = dist8; if(dist8 < min1){ min2 = min1; min1 = dist8; } else if(dist8 < min2) min2 = dist8; if(min1 == min2) result = value; else result = 0; if(min1 == 0) result = 0; return(result); } /* ends mat_d */ /********************************************* * * file d:\cips\segment.c * * Functions: This file contains * adaptive_threshold_segmentation * append_stack_files * copy_stack_files * find_peaks * find_valley_point * grow * insert_into_peaks * insert_into_deltas * label_and_check_neighbors * manual_threshold_segmentation * peak_threshold_segmentation * peaks_high_low * push_data_onto_stack_file * pop_data_off_of_stack_file * threshold_image_array * valley_high_low * valley_threshold_segmentation * get_segmentation_options * * Purpose: * These functions are part of histogram * based image segmentation. * * External Calls: * wtiff.c - round_off_image_size * create_file_if_needed * write_array_into_tiff_image * tiff.c - read_tiff_header * rtiff.c - read_tiff_image * numcvrt.c - get_integer * get_short * * Modifications: * October 1992 - created * ************************************************/ /************************************************** * * manual_threshold_segmentation(... * * This function segments an image using thresholding * given the hi and low values of the threshold * by the calling routine. It reads in an image * and writes the result to the output image. * * If the segment parameter is 0, you only * threshold the array - you do not segment. * ***************************************************/ manual_threshold_segmentation(in_name, out_name, the_image, out_image, il, ie, ll, le, hi, low, value, segment) char in_name[], out_name[]; int il, ie, ll, le, segment; short hi, low, the_image[ROWS][COLS], out_image[ROWS][COLS], value; { int length, width; struct tiff_header_struct image_header; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); threshold_image_array(the_image, out_image, hi, low, value); if(segment == 1) grow(out_image, value); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends manual_threshold_segmentation */ /************************************************ * * peak_threshold_segmentation(... * * This function segments an image using * thresholding. It uses the histogram peaks * to find the hi and low values of the * threshold. * * If the segment parameter is 0, you only * threshold the array - you do not segment. * *************************************************/ peak_threshold_segmentation(in_name, out_name, the_image, out_image, il, ie, ll, le, value, segment) char in_name[], out_name[]; int il, ie, ll, le, segment; short the_image[ROWS][COLS], out_image[ROWS][COLS], value; { int length, peak1, peak2, width; short hi, low; struct tiff_header_struct image_header; unsigned long histogram[GRAY_LEVELS+1]; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); zero_histogram(histogram); calculate_histogram(the_image, histogram); smooth_histogram(histogram); find_peaks(histogram, &peak1, &peak2); peaks_high_low(histogram, peak1, peak2, &hi, &low); threshold_image_array(the_image, out_image, hi, low, value); if(segment == 1) grow(out_image, value); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends peak_threshold_segmentation */ /************************************************ * * valley_threshold_segmentation(... * * This function segments an image using * thresholding. It uses the histogram valleys * to find the hi and low values of the * threshold. * * If the segment parameter is 0, you only * threshold the array - you do not segment. * *************************************************/ valley_threshold_segmentation(in_name, out_name, the_image, out_image, il, ie, ll, le, value, segment) char in_name[], out_name[]; int il, ie, ll, le, segment; short the_image[ROWS][COLS], out_image[ROWS][COLS], value; { int length, peak1, peak2, width; short hi, low; struct tiff_header_struct image_header; unsigned long histogram[GRAY_LEVELS+1]; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); zero_histogram(histogram); calculate_histogram(the_image, histogram); smooth_histogram(histogram); find_peaks(histogram, &peak1, &peak2); valley_high_low(histogram, peak1, peak2, &hi, &low); threshold_image_array(the_image, out_image, hi, low, value); if(segment == 1) grow(out_image, value); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends valley_threshold_segmentation */ /************************************************ * * adaptive_threshold_segmentation(... * * This function segments an image using * thresholding. It uses two passes * to find the hi and low values of the * threshold. The first pass uses the peaks * of the histogram to find the hi and low * threshold values. It thresholds the image * using these hi lows and calculates the means * of the object and background. Then we use * these means as new peaks to calculate new * hi and low values. Finally, we threshold * the image again using these second hi low * hi low values. * * If the segment parameter is 0, you only * threshold the array - you do not segment. * *************************************************/ adaptive_threshold_segmentation(in_name, out_name, the_image, out_image, il, ie, ll, le, value, segment) char in_name[], out_name[]; int il, ie, ll, le, segment; short the_image[ROWS][COLS], out_image[ROWS][COLS], value; { int length, peak1, peak2, width; short background, hi, low, object; struct tiff_header_struct image_header; unsigned long histogram[GRAY_LEVELS+1]; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); zero_histogram(histogram); calculate_histogram(the_image, histogram); smooth_histogram(histogram); find_peaks(histogram, &peak1, &peak2); peaks_high_low(histogram, peak1, peak2, &hi, &low); threshold_and_find_means(the_image, out_image, hi, low, value, &object, &background); peaks_high_low(histogram, object, background, &hi, &low); threshold_image_array(the_image, out_image, hi, low, value); if(segment == 1) grow(out_image, value); write_array_into_tiff_image(out_name, out_image, il, ie, ll, le); } /* ends adaptive_threshold_segmentation */ /************************************************** * * threshold_image_array(... * * This function thresholds an input image array * and produces a binary output image array. * If the pixel in the input array is between * the hi and low values, then it is set to value. * Otherwise, it is set to 0. * ***************************************************/ threshold_image_array(in_image, out_image, hi, low, value) short hi, low, in_image[ROWS][COLS], out_image[ROWS][COLS], value; { int counter = 0, i, j; for(i=0; i= low && in_image[i][j] <= hi){ out_image[i][j] = value; counter++; } else out_image[i][j] = 0; } /* ends loop over j */ } /* ends loop over i */ printf("\n\tTIA> set %d points", counter); } /* ends threshold_image_array */ /************************************************** * * threshold_and_find_means(... * * This function thresholds an input image array * and produces a binary output image array. * If the pixel in the input array is between * the hi and low values, then it is set to value. * Otherwise, it is set to 0. * ***************************************************/ threshold_and_find_means(in_image, out_image, hi, low, value, object_mean, background_mean) short *background_mean, hi, low, in_image[ROWS][COLS], *object_mean, out_image[ROWS][COLS], value; { int counter = 0, i, j; unsigned long object = 0, background = 0; for(i=0; i= low && in_image[i][j] <= hi){ out_image[i][j] = value; counter++; object = object + in_image[i][j]; } else{ out_image[i][j] = 0; background = background + in_image[i][j]; } } /* ends loop over j */ } /* ends loop over i */ object = object/counter; background = background/((ROWS*COLS)-counter); *object_mean = (short)(object); *background_mean = (short)(background); printf("\n\tTAFM> set %d points", counter); printf("\n\tTAFM> object=%d background=%d", *object_mean, *background_mean); } /* ends threshold_and_find_means */ /********************************************** * * grow(... * * This function is an object detector. * Its input is an binary image array * containing 0's and value's. * It searches through the image and connects * the adjacent values. * ***********************************************/ grow(binary, value) short binary[ROWS][COLS], value; { char name[80]; int first_call, i, j, object_found, pointer, pop_i, pop_j, stack_empty, stack_file_in_use; short g_label, stack[STACK_SIZE][2]; /************************************* * * Now begin the process of growing * regions. * **************************************/ g_label = 2; object_found = 0; first_call = 1; for(i=0; i found %d objects", g_label); } /* ends grow */ /******************************************** * * label_and_check_neighbors(... * * This function labels a pixel with an object * label and then checks the pixel's 8 * neighbors. If any of the neigbors are * set, then they are also labeled. * ***********************************************/ label_and_check_neighbor(binary_image, stack, g_label, stack_empty, pointer, r, e, value, stack_file_in_use, first_call) int e, *first_call, *pointer, r, *stack_empty, *stack_file_in_use; short binary_image[ROWS][COLS], g_label, stack[STACK_SIZE][2], value; { int already_labeled = 0, i, j; if (binary_image[r][e] == g_label) already_labeled = 1; binary_image[r][e] = g_label; /*************************************** * * Look at the 8 neighors of the * point r,e. * * Ensure the points you are checking * are in the image, i.e. not less * than zero and not greater than * ROWS-1 or COLS-1. * ***************************************/ for(i=(r-1); i<=(r+1); i++){ for(j=(e-1); j<=(e+1); j++){ if((i>=0) && (i<=ROWS-1) && (j>=0) && (j<=COLS-1)){ if(binary_image[i][j] == value){ *pointer = *pointer + 1; stack[*pointer][0] = i; /* PUSH */ stack[*pointer][1] = j; /* OPERATION */ *stack_empty = 0; if(*pointer >= (STACK_SIZE - STACK_FILE_LENGTH)){ push_data_onto_stack_file(stack, pointer, first_call); *stack_file_in_use = 1; } /* ends if *pointer >= STACK_SIZE - STACK_FILE_LENGTH*/ } /* end of if binary_image == value */ } /* end if i and j are on the image */ } /* ends loop over i rows */ } /* ends loop over j columns */ } /* ends label_and_check_neighbors */ /**************************************** * * push_data_onto_stack_file(... * * This function takes the stack array * and pushes it onto the stack file. * *****************************************/ push_data_onto_stack_file(stack, pointer, first_call) int *first_call, *pointer; short stack[STACK_SIZE][2]; { char backup_file_name[MAX_NAME_LENGTH]; FILE *backup_file_pointer, *stack_file_pointer; int diff, i; short holder[STACK_FILE_LENGTH][2]; printf("\nSFO> Start of push_data_onto_stack "); diff = STACK_SIZE - STACK_FILE_LENGTH; /******************************************* * * Copy the elements to be stored to the * stack file into holder * ********************************************/ for(i=0; i Could not open stack file"); else{ /*printf("\n\nSFO> Writing to stack file");*/ fwrite(holder, sizeof(holder), 1, stack_file_pointer); fclose(stack_file_pointer); } /* ends else could not open stack_file */ } /* ends if *first_call == 1 */ else{ /* else stack file has been used already */ strcpy(backup_file_name, STACK_FILE); strcat(backup_file_name, ".bak"); if((backup_file_pointer = fopen(backup_file_name, "wb")) == NULL) printf("\nSFO> Could not open backup file"); else{ /*printf("\n\nSFO> Writing to backup file");*/ fwrite(holder, sizeof(holder), 1, backup_file_pointer); fclose(backup_file_pointer); } /* ends else could not open backup_file */ append_stack_files(backup_file_name, STACK_FILE, holder); copy_stack_files(backup_file_name, STACK_FILE, holder); } /* ends else first_call != 1 */ printf("--- End of push_data_onto_stack"); } /* ends push_data_onto_stack_file */ /**************************************** * * pop_data_off_of_stack_file(... * * This function pops the stack array * off of the stack file. * *****************************************/ pop_data_off_of_stack_file(stack, pointer, stack_file_in_use) int *pointer, *stack_file_in_use; short stack[STACK_SIZE][2]; { char backup_file_name[MAX_NAME_LENGTH]; FILE *backup_file_pointer, *stack_file_pointer; int i; long write_counter; short holder[STACK_FILE_LENGTH][2], holder2[STACK_FILE_LENGTH][2]; /******************************************* * * POP - Read 1 time from stack * Copy the remainder of stack to * stack.bak * Copy stack.bak to stack * This has the effect of popping off * of the stack. * * Read the holder array from the stack file. * Open the stack file for reading in binary * mode. * * If it requires more than one write to * copy the remainder of stack to * stack.bak then there is still data in the * stack file so set stack_file_in_use = 1. * Else set it to 0. * **********************************************/ printf("\nSFO> Start of pop_data_off_of_stack "); write_counter = 0; strcpy(backup_file_name, STACK_FILE); strcat(backup_file_name, ".bak"); if( (stack_file_pointer = fopen(STACK_FILE, "rb")) == NULL) printf("\nSFO> Could not open stack file"); else{ /*printf("\n\nSFO> Reading from stack file");*/ fread(holder, sizeof(holder), 1, stack_file_pointer); backup_file_pointer = fopen(backup_file_name, "wb"); while( fread(holder2, sizeof(holder2), 1, stack_file_pointer) ){ fwrite(holder2, sizeof(holder2), 1, backup_file_pointer); ++write_counter; } /* ends while reading */ if(write_counter > 0) *stack_file_in_use = 1; else *stack_file_in_use = 0; fclose(backup_file_pointer); fclose(stack_file_pointer); } /* ends else could not open stack file */ copy_stack_files(backup_file_name, STACK_FILE, holder2); for(i=0; i Cannot open file %s", first_file); if((second = fopen(second_file, "rb")) == NULL) printf("\n\nSFO> Cannot open file %s", second_file); /***************************************** * * Seek to the end of the first file and * to the beginning of the second file. * *******************************************/ fseek(first, 0L, 2); fseek(second, 0L, 0); while(fread(holder, sizeof(holder), 1, second) ){ fwrite(holder, sizeof(holder), 1, first); } /* ends while reading */ fclose(first); fclose(second); } /* ends append_stack_files */ /******************************************** * * copy_stack_files(... * * Copy the first file to the second. * **********************************************/ copy_stack_files(first_file, second_file, holder) char first_file[], second_file[]; short holder[STACK_FILE_LENGTH][2]; { FILE *first, *second; int i; if( (first = fopen(first_file, "rb")) == NULL) printf("\n\nSFO> Cannot open file %s", first_file); if( (second = fopen(second_file, "wb")) == NULL) printf("\n\nSFO> Cannot open file %s", second_file); /****************************************** * * Seek to the beginning of the first file. * *******************************************/ fseek(first, 0L, 0); while( fread(holder, sizeof(holder), 1, first) ){ fwrite(holder, sizeof(holder), 1, second); } /* ends while reading */ fclose(first); fclose(second); } /* ends copy_stack_files */ /******************************************** * * find_peaks(... * * This function looks through the histogram * array and finds the two highest peaks. * The peaks must be separated, cannot be * next to each other, by a spacing defined * in cips.h. * * The peaks array holds the peak value * in the first place and its location in * the second place. * *********************************************/ find_peaks(histogram, peak1, peak2) unsigned long histogram[]; int *peak1, *peak2; { int distance[PEAKS], peaks[PEAKS][2]; int i, j=0, max=0, max_place=0; for(i=0; i0; i--) if(distance[i] > PEAK_SPACE) *peak2 = peaks[i][1]; } /* ends find_peaks */ /******************************************** * * insert_into_peaks(... * * This function takes a value and its * place in the histogram and inserts them * into a peaks array. This helps us rank * the the peaks in the histogram. * * The objective is to build a list of * histogram peaks and thier locations. * * The peaks array holds the peak value * in the first place and its location in * the second place. * *********************************************/ insert_into_peaks(peaks, max, max_place) int max, max_place, peaks[PEAKS][2]; { int i, j; /* first case */ if(max > peaks[0][0]){ for(i=PEAKS-1; i>0; i--){ peaks[i][0] = peaks[i-1][0]; peaks[i][1] = peaks[i-1][1]; } peaks[0][0] = max; peaks[0][1] = max_place; } /* ends if */ /* middle cases */ for(j=0; j peaks[j+1][0]){ for(i=PEAKS-1; i>j+1; i--){ peaks[i][0] = peaks[i-1][0]; peaks[i][1] = peaks[i-1][1]; } peaks[j+1][0] = max; peaks[j+1][1] = max_place; } /* ends if */ } /* ends loop over j */ /* last case */ if(max < peaks[PEAKS-2][0] && max > peaks[PEAKS-1][0]){ peaks[PEAKS-1][0] = max; peaks[PEAKS-1][1] = max_place; } /* ends if */ } /* ends insert_into_peaks */ /******************************************** * * peaks_high_low(... * * This function uses the histogram array * and the peaks to find the best high and * low threshold values for the threshold * function. You want the hi and low values * so that you will threshold the image around * the smaller of the two "humps" in the * histogram. This is because the smaller * hump represents the objects while the * larger hump represents the background. * *********************************************/ peaks_high_low(histogram, peak1, peak2, hi, low) int peak1, peak2; short *hi, *low; unsigned long histogram[]; { int i, mid_point; unsigned long sum1 = 0, sum2 = 0; if(peak1 > peak2) mid_point = ((peak1 - peak2)/2) + peak2; if(peak1 < peak2) mid_point = ((peak2 - peak1)/2) + peak1; for(i=0; i= sum2){ *low = mid_point; *hi = GRAY_LEVELS; } else{ *low = 0; *hi = mid_point; } } /* ends peaks_high_low */ /******************************************** * * valley_high_low(... * * This function uses the histogram array * and the valleys to find the best high and * low threshold values for the threshold * function. You want the hi and low values * so that you will threshold the image around * the smaller of the two "humps" in the * histogram. This is because the smaller * hump represents the objects while the * larger hump represents the background. * *********************************************/ valley_high_low(histogram, peak1, peak2, hi, low) int peak1, peak2; short *hi, *low; unsigned long histogram[]; { int i, valley_point; unsigned long sum1 = 0, sum2 = 0; find_valley_point(histogram, peak1, peak2, &valley_point); /*printf("\nVHL> valley point is %d", valley_point);*/ for(i=0; i= sum2){ *low = valley_point; *hi = GRAY_LEVELS; } else{ *low = 0; *hi = valley_point; } } /* ends valley_high_low */ /******************************************** * * find_valley_point(... * * This function finds the low point of * the valley between two peaks in a * histogram. It starts at the lowest * peak and works its way up to the * highest peak. Along the way, it looks * at each point in the histogram and inserts * them into a list of points. When done, * it has the location of the smallest histogram * point - that is the valley point. * * The deltas array holds the delta value * in the first place and its location in * the second place. * *********************************************/ find_valley_point(histogram, peak1, peak2, valley_point) int peak1, peak2, *valley_point; unsigned long histogram[]; { int deltas[PEAKS][2], delta_hist, i; for(i=0; i0; i--){ deltas[i][0] = deltas[i-1][0]; deltas[i][1] = deltas[i-1][1]; } deltas[0][0] = value; deltas[0][1] = place; } /* ends if */ /* middle cases */ for(j=0; j deltas[j][0] && value < deltas[j+1][0]){ for(i=PEAKS-1; i>j+1; i--){ deltas[i][0] = deltas[i-1][0]; deltas[i][1] = deltas[i-1][1]; } deltas[j+1][0] = value; deltas[j+1][1] = place; } /* ends if */ } /* ends loop over j */ /* last case */ if(value > deltas[PEAKS-2][0] && value < deltas[PEAKS-1][0]){ deltas[PEAKS-1][0] = value; deltas[PEAKS-1][1] = place; } /* ends if */ } /* ends insert_into_deltas */ /******************************************** * * get_segmentation_options(... * * This function interacts with the user * to obtain the options for image * segmentation. * *********************************************/ get_segmentation_options(method, hi, low, value) char method[]; short *hi, *low, *value; { int i, not_finished = 1, response; while(not_finished){ printf( "\n\nThe image segmentation options are:\n"); printf("\n\t1. Method is %s", method); printf("\n\t (options are manual peaks"); printf( " valleys adapative)"); printf("\n\t2. Value is %d", *value); printf("\n\t3. Hi is %d", *hi); printf("\n\t4. Low is %d", *low); printf("\n\t Hi and Low needed only for"); printf( " manual method"); printf("\n\nEnter choice (0 = no change):_\b"); get_integer(&response); if(response == 0) not_finished = 0; if(response == 1){ printf("\nEnter method (options are:"); printf(" manual peaks valleys adaptive)\n\t"); gets(method); } if(response == 2){ printf("\nEnter value: ___\b\b\b"); get_short(value); } if(response == 3){ printf("\nEnter hi: ___\b\b\b"); get_short(hi); } if(response == 4){ printf("\nEnter low: ___\b\b\b"); get_short(low); } } /* ends while not_finished */ } /* ends get_segmentation_options */ /******************************************** * * get_threshold_options(... * * This function interacts with the user * to obtain the options for image * threshold. * *********************************************/ get_threshold_options(method, hi, low, value) char method[]; short *hi, *low, *value; { int i, not_finished = 1, response; while(not_finished){ printf("\n\nThe image threshold options are:\n"); printf("\n\t1. Method is %s", method); printf("\n\t (options are manual peaks"); printf( " valleys adapative)"); printf("\n\t2. Value is %d", *value); printf("\n\t3. Hi is %d", *hi); printf("\n\t4. Low is %d", *low); printf("\n\t Hi and Low needed only for"); printf( " manual method"); printf("\n\nEnter choice (0 = no change):_\b"); get_integer(&response); if(response == 0) not_finished = 0; if(response == 1){ printf("\nEnter method (options are:"); printf(" manual peaks valleys adaptive)\n\t"); gets(method); } if(response == 2){ printf("\nEnter value: ___\b\b\b"); get_short(value); } if(response == 3){ printf("\nEnter hi: ___\b\b\b"); get_short(hi); } if(response == 4){ printf("\nEnter low: ___\b\b\b"); get_short(low); } } /* ends while not_finished */ } /* ends get_threshold_options */ /*********************************************** * * file d:\cips\segment2.c * * Functions: This file contains * find_cutoff_point * edge_region * gray_shade_region * edge_gray_shade_region * pixel_grow * pixel_label_and_check_neighbors * is_close * erode_image_array * get_edge_region_options * * Purpose: * These function implement the three * segmentation techniques in Image * Processing part 10. * * External Calls: * wtiff.c - round_off_image_size * create_file_if_needed * write_array_into_tiff_image * tiff.c - read_tiff_header * rtiff.c - read_tiff_image * numcvrt.c - get_integer * edges.c - quick_edge * homogeneity * difference_edge * contrast_edge * gaussian_edge * range * variance * detect_edges * hist.c - calculate_histogram * zero_histogram * thresh.c - threshold_image_array * * Modifications: * 5 December 1992 - created * *************************************************/ /******************************************* * * find_cutoff_point(.. * * This function looks at a histogram * and sets a cuttoff point at a given * percentage of pixels. * For example, if percent=0.6, you * start at 0 in the histogram and count * up until you've hit 60% of the pixels. * Then you stop and return that pixel * value. * ********************************************/ find_cutoff_point(histogram, percent, cutoff) unsigned long histogram[]; float percent; short *cutoff; { float fd, fsum, sum_div; int i, looking; long lc, lr, num=0, sum=0; sum = 0; i = 0; lr = (long)(ROWS); lc = (long)(COLS); num = lr*lc; fd = (float)(num); while(looking){ fsum = (float)(sum); sum_div = fsum/fd; if(sum_div >= percent) looking = 0; else sum = sum + histogram[i++]; } /* ends while looking */ if(i >= 256) i = 255; *cutoff = i; printf("\nCutoff is %d sum=%ld", *cutoff, sum); } /* ends find_cutoff_point */ /******************************************* * * edge_region(.. * * This function segments an image by * growing regions inside of edges. * The steps are: * . detect edges * . threshold edge output to a * percent value * . remove edges from consideration * . grow regions * *******************************************/ edge_region(in_name, out_name, the_image, out_image, il, ie, ll, le, edge_type, min_area, max_area, diff, percent, set_value, erode) char in_name[], out_name[]; float percent; int edge_type, il, ie, ll, le; short diff, erode, max_area, min_area, set_value, the_image[ROWS][COLS], out_image[ROWS][COLS]; { int a, b, count, i, j, k, length, width; short cutoff; struct tiff_header_struct image_header; unsigned long histogram[GRAY_LEVELS+1]; create_file_if_needed(in_name, out_name, out_image); read_tiff_image(in_name, the_image, il, ie, ll, le); /*************************** * * Detect the edges. Do * not threshold. * ****************************/ if(edge_type == 1 || edge_type == 2 || edge_type == 3) detect_edges(in_name, out_name, the_image, out_image, il, ie, ll, le, edge_type, 0, 0); if(edge_type == 4){ quick_edge(in_name, out_name, the_image, out_image, il, ie, ll, le, 0, 0); } /* ends if 4 */ if(edge_type == 5){ homogeneity(in_name, out_name, the_image, out_image, il, ie, ll, le, 0, 0); } /* ends if 5 */ if(edge_type == 6){ difference_edge(in_name, out_name, the_image, out_image, il, ie, ll, le, 0, 0); } /* ends if 6 */ if(edge_type == 7){ contrast_edge(in_name, out_name, the_image, out_image, il, ie, ll, le, 0, 0); } /* ends if 7 */ if(edge_type == 8){ gaussian_edge(in_name, out_name, the_image, out_image, il, ie, ll, le, 3, 0, 0); } /* ends if 8 */ if(edge_type == 10){ range(in_name, out_name, the_image, out_image, il, ie, ll, le, 3, 0, 0); } /* ends if 10 */ if(edge_type == 11){ variance(in_name, out_name, the_image, out_image, il, ie, ll, le, 0, 0); } /* ends if 11 */ /**write_array_into_tiff_image("f:e1.tif", out_image, il, ie, ll, le);**/ /* copy out_image to the_image */ for(i=0; i= min_area && count <= max_area) ++g_label; /********************************** * * Remove the object from the * output. Set all pixels in the * object you are removing to * FORGET_IT. * **********************************/ else{ for(ii=0; ii found %d objects", g_label); } /* ends pixel_grow */ /******************************************** * * pixel_label_and_check_neighbors(... * * This function labels a pixel with an object * label and then checks the pixel's 8 * neighbors. If any of the neigbors are * set, then they are also labeled. * * It also updates the target or ave pixel * value of the pixels in the region being * grown. * ***********************************************/ pixel_label_and_check_neighbor(input_image, output_image, target, sum, count, stack, g_label, stack_empty, pointer, r, e, diff, stack_file_in_use, first_call) int *count, e, *first_call, *pointer, r, *stack_empty, *stack_file_in_use; short input_image[ROWS][COLS], output_image[ROWS][COLS], g_label, *sum, *target, stack[STACK_SIZE][2], diff; { int already_labeled = 0, i, j; if (output_image[r][e] != 0) already_labeled = 1; output_image[r][e] = g_label; *count = *count + 1; if(*count > 1){ *sum = *sum + input_image[r][e]; *target = *sum / *count; } /*************************************** * * Look at the 8 neighors of the * point r,e. * * Ensure the points are close enough * to the target and do not equal * FORGET_IT. * * Ensure the points you are checking * are in the image, i.e. not less * than zero and not greater than * ROWS-1 or COLS-1. * ***************************************/ for(i=(r-1); i<=(r+1); i++){ for(j=(e-1); j<=(e+1); j++){ if((i>=0) && (i<=ROWS-1) && (j>=0) && (j<=COLS-1)){ if( input_image[i][j] != FORGET_IT && is_close(input_image[i][j], *target, diff) && output_image[i][j] == 0){ *pointer = *pointer + 1; stack[*pointer][0] = i; /* PUSH */ stack[*pointer][1] = j; /* OPERATION */ *stack_empty = 0; if(*pointer >= (STACK_SIZE - STACK_FILE_LENGTH)){ push_data_onto_stack_file(stack, pointer, first_call); *stack_file_in_use = 1; } /* ends if *pointer >= STACK_SIZE - STACK_FILE_LENGTH*/ } /* ends if is_close */ } /* end if i and j are on the image */ } /* ends loop over i rows */ } /* ends loop over j columns */ } /* ends pixel_label_and_check_neighbors */ /******************************************** * * is_close(... * * This function tests to see if two pixel * values are close enough together. It * uses the delta parameter to make this * judgement. * ***********************************************/ is_close(a, b, delta) short a, b, delta; { int result = 0; short diff; diff = a-b; if(diff < 0) diff = diff*(-1); if(diff < delta) result = 1; return(result); } /* ends is_close */ /******************************************* * * erode_image_array(.. * * This function erodes pixels. If a pixel * equals value and has more than threshold * neighbors equal to 0, then set that * pixel in the output to 0. * *******************************************/ erode_image_array(the_image, out_image, value, threshold) short the_image[ROWS][COLS], out_image[ROWS][COLS], threshold, value; { int a, b, count, i, j, k, length, width; /*************************** * * Loop over image array * ****************************/ for(i=0; i threshold) out_image[i][j] = 0; } /* ends if the_image == value */ } /* ends loop over j */ } /* ends loop over i */ } /* ends erode_image_array */ /******************************************** * * get_edge_region_options(... * * This function interacts with the user to * get the options needed to call the * edge and region based segmentation * routines. * ********************************************/ get_edge_region_options(method, edge_type, min_area, max_area, set_value, diff, percent, erode) char method[]; float *percent; int *edge_type; short *diff, *erode, *min_area, *max_area, *set_value; { int not_finished = 1, response; while(not_finished){ printf("\n\nEdge Region Segmentation Options:"); printf("\n\t1. Method is %s", method); printf("\n\t Recall: Edge, Gray shade, " "Combination"); printf("\n\t2. Edge type is %d", *edge_type); printf("\n\t Recall: "); printf("\n\t 1=Prewitt 2=Kirsch"); printf("\n\t 3=Sobel 4=quick"); printf("\n\t 5=homogeneity 6=difference"); printf("\n\t 7=contrast 8=gaussian"); printf("\n\t 10=range 11=variance"); printf("\n\t3. Min area is %d", *min_area); printf("\n\t4. Max area is %d", *max_area); printf("\n\t5. Set value is %d", *set_value); printf("\n\t6. Difference value is %d", *diff); printf("\n\t7. Threshold percentage is %f", *percent); printf("\n\t8. Erode is %d", *erode); printf("\n\nEnter choice (0 = no change) _\b"); get_integer(&response); if(response == 0){ not_finished = 0; } if(response == 1){ printf("\n\t Recall: Edge, Gray shade, " "Combination"); printf("\n\t> "); gets(method); } if(response == 2){ printf("\n\t Recall:"); printf("\n\t 1=Prewitt 2=Kirsch"); printf("\n\t 3=Sobel 4=quick"); printf("\n\t 5=homogeneity 6=difference"); printf("\n\t 7=contrast 8=gaussian"); printf("\n\t 10=range 11=variance"); printf("\n\t__\b"); get_integer(edge_type); } if(response == 3){ printf("\nEnter min area:__\b\b"); get_integer(min_area); } if(response == 4){ printf("\nEnter max area:__\b\b"); get_integer(max_area); } if(response == 5){ printf("\nEnter set value:__\b\b"); get_integer(set_value); } if(response == 6){ printf("\nEnter difference:__\b\b"); get_integer(diff); } if(response == 7){ printf("\nEnter threshold percentage:__\b\b"); get_float(percent); } if(response == 8){ printf("\nEnter erode:__\b\b"); get_integer(erode); } } /* ends while not_finished */ } /* ends get_edge_region_options */