/********************************************** * * file 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: * none * * * Modifications: * 7 March 1993 - created * 21 August 1998 - modified to work on entire * images at once. * ************************************************/ #include "cips.h" /******************************************* * * 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(the_image, out_image, value, threshold, number, rows, cols) int number; short **the_image, **out_image, threshold, value; long cols, rows; { int a, b, count, i, j, k; thinning(the_image, out_image, value, threshold, 1, rows, cols); if(number > 1){ count = 1; while(count < number){ count++; thinning(the_image, out_image, value, threshold, 1, rows, cols); } /* ends while */ } /* ends if number > 1 */ dilation(the_image, out_image, value, threshold, rows, cols); } /* ends special_opening */ /******************************************* * * 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(the_image, out_image, value, threshold, once_only, rows, cols) int once_only; short **the_image, **out_image, threshold, value; long cols, rows; { int a, b, big_count, count, i, j, k, not_finished; 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 */ /******************************************* * * 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(the_image, out_image, value, threshold, number, rows, cols) int number; short **the_image, **out_image, threshold, value; long cols, rows; { int a, b, count, i, j, k; dilate_not_join(the_image, out_image, value, threshold, rows, cols); if(number > 1){ count = 1; while(count < number){ count++; dilate_not_join(the_image, out_image, value, threshold, rows, cols); } /* ends while */ } /* ends if number > 1 */ erosion(the_image, out_image, value, threshold, rows, cols); } /* ends special_closing */ /******************************************* * * 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(the_image, out_image, value, threshold, rows, cols) short **the_image, **out_image, threshold, value; long cols, rows; { int a, b, count, i, j, k; 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 */ /******************************************* * * 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(the_image, out_image, value, rows, cols) short **the_image, **out_image, value; long cols, rows; { int a, b, count, i, j, k; 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(the_image, out_image, value, rows, cols) short **the_image, **out_image, value; long cols, rows; { int a, b, count, i, j, k, length, width; 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 */