diff options
-rw-r--r-- | include/lib/seg/mask_data.h | 6 | ||||
-rw-r--r-- | include/lib/seg/util.h | 11 | ||||
-rw-r--r-- | src/lib/seg/mask_data.c | 37 | ||||
-rw-r--r-- | src/lib/seg/util.c | 85 | ||||
-rw-r--r-- | src/main.c | 98 |
5 files changed, 132 insertions, 105 deletions
diff --git a/include/lib/seg/mask_data.h b/include/lib/seg/mask_data.h index f2803e6..8e2ae3a 100644 --- a/include/lib/seg/mask_data.h +++ b/include/lib/seg/mask_data.h @@ -56,4 +56,10 @@ bool_t in_uint16_t_tree(struct AVLNode* root, uint16_t value); // Assumption: Contiguous labeling struct AVLNode* get_small_labels(struct AVLNode* removal_tree, struct AVLNode* label_tree, size_t min_area, size_t min_perimeter); +// Get mask label data +struct AVLNode* get_mask_data(uint16_t* masks, uint32_t width, uint32_t height); + +// Filter out small masks in mask +void filter_small_masks(uint16_t* masks, uint32_t width, uint32_t height, size_t min_area, size_t min_perimeter); + #endif diff --git a/include/lib/seg/util.h b/include/lib/seg/util.h index fcafff6..c54b0e0 100644 --- a/include/lib/seg/util.h +++ b/include/lib/seg/util.h @@ -13,13 +13,13 @@ size_t xy_to_coord(size_t x, size_t y, uint32_t width, uint32_t height); bool_t is_on_mask_boundary(uint16_t* mask, uint32_t width, uint32_t height, size_t x, size_t y); // Dilate masks by one 4-connected pixel -uint16_t* dilate(uint16_t* mask, uint32_t width, uint32_t height); +void dilate(uint16_t** mask, uint32_t width, uint32_t height); // Erode masks by one 4-connected pixel -uint16_t* erode(uint16_t* mask, uint32_t width, uint32_t height); +void erode(uint16_t** mask, uint32_t width, uint32_t height); // Close up masks by N-pixels -uint16_t* closeup(uint16_t* mask, uint32_t width, uint32_t height, size_t count); +void closeup(uint16_t** mask, uint32_t width, uint32_t height, size_t count); // Combine Label Masks // For all empty spaces in the destination, put the extra label if it exists @@ -34,4 +34,9 @@ uint16_t* tif_to_labels(char* tif_file_name, uint32_t *width, uint32_t *height, // Convert mask to bitmap struct bitmap_t* uint16_to_bitmap(uint16_t* buffer, uint32_t width, uint32_t height); +// Reduce a mask to the contiguous regions +// Automatically update pointer to contiguous mask +// Freeing previous mask +void reduce_contiguous_regions(uint16_t** masks_p, uint32_t width, uint32_t height, uint16_t* total_labels); + #endif diff --git a/src/lib/seg/mask_data.c b/src/lib/seg/mask_data.c index 2f3a51a..8c4b037 100644 --- a/src/lib/seg/mask_data.c +++ b/src/lib/seg/mask_data.c @@ -1,4 +1,5 @@ #include <lib/seg/mask_data.h> +#include <lib/seg/util.h> #include <stdio.h> @@ -224,3 +225,39 @@ struct AVLNode* get_small_labels(struct AVLNode* removal_tree, struct AVLNode* l } return return_tree; } + +// Get mask label data +struct AVLNode* get_mask_data(uint16_t* masks, uint32_t width, uint32_t height) +{ + struct AVLNode* root = NULL; + for (size_t y = 0; y < height; y++) { + for (size_t x = 0; x < width; x++) { + size_t coord = x + y*width; + if (masks[coord] != 0) { + root = increase_label_area_alloc(root, masks[coord]); + if (is_on_mask_boundary(masks, width, height, x, y)) { + increase_label_perimeter(root, masks[coord]); + } + } + } + } + return root; +} + +// Filter out small masks in mask +void filter_small_masks(uint16_t* masks, uint32_t width, uint32_t height, size_t min_area, size_t min_perimeter) +{ + struct AVLNode* root = get_mask_data(masks, width, height); + struct AVLNode* small_label_tree = NULL; + small_label_tree = get_small_labels(NULL, root, min_area, min_perimeter); + for (size_t y = 0; y < height; y++) { + for (size_t x = 0; x < width; x++) { + size_t coord = x + y*width; + if (in_uint16_t_tree(small_label_tree, masks[coord])) { + masks[coord] = 0; + } + } + } + free_avl_tree(small_label_tree); + free_avl_tree_nodes(root); +} diff --git a/src/lib/seg/util.c b/src/lib/seg/util.c index 10b8fa8..a45f6c8 100644 --- a/src/lib/seg/util.c +++ b/src/lib/seg/util.c @@ -1,4 +1,4 @@ -#include <lib/seg/util.h> + #include <lib/seg/util.h> #include <lib/algo/flood_fill.h> #include <lib/png.h> #include <tiffio.h> @@ -51,7 +51,7 @@ bool_t is_on_mask_boundary(uint16_t* mask, uint32_t width, uint32_t height, size } // Dilate masks by one 4-connected pixel -uint16_t* dilate(uint16_t* mask, uint32_t width, uint32_t height) +uint16_t* _dilate(uint16_t* mask, uint32_t width, uint32_t height) { uint16_t *new_mask = (uint16_t*)calloc(width*height,sizeof(uint16_t)); for (size_t y = 0; y < height; y++) { @@ -95,8 +95,18 @@ uint16_t* dilate(uint16_t* mask, uint32_t width, uint32_t height) return new_mask; } +// Dilate masks by one 4-connected pixel +void dilate(uint16_t** mask, uint32_t width, uint32_t height) +{ + uint16_t *new_mask = _dilate(*mask, width, height); + if (new_mask != NULL) { + free(*mask); + *mask = new_mask; + } +} + // Erode masks by one 4-connected pixel -uint16_t* erode(uint16_t* mask, uint32_t width, uint32_t height) +uint16_t* _erode(uint16_t* mask, uint32_t width, uint32_t height) { uint16_t *new_mask = (uint16_t*)calloc(width*height,sizeof(uint16_t)); for (size_t y = 0; y < height; y++) { @@ -141,20 +151,26 @@ uint16_t* erode(uint16_t* mask, uint32_t width, uint32_t height) return new_mask; } +// Erode masks by one 4-connected pixel +void erode(uint16_t** mask, uint32_t width, uint32_t height) +{ + uint16_t *new_mask = _erode(*mask, width, height); + if (new_mask != NULL) { + free(*mask); + *mask = new_mask; + } +} + // Close up masks by N-pixels -uint16_t* closeup(uint16_t* mask, uint32_t width, uint32_t height, size_t num_pixels) +uint16_t* _closeup(uint16_t* mask, uint32_t width, uint32_t height, size_t num_pixels) { uint16_t *new_mask = (uint16_t*)calloc(width*height,sizeof(uint16_t)); memcpy(new_mask, mask, width*height*sizeof(uint16_t)); for (size_t count = 0; count < num_pixels; count++) { - uint16_t *new_labels = dilate(new_mask, width, height); - free(new_mask); - new_mask = new_labels; + dilate(&new_mask, width, height); } for (size_t count = 0; count < num_pixels; count++) { - uint16_t *new_labels = erode(new_mask, width, height); - free(new_mask); - new_mask = new_labels; + erode(&new_mask, width, height); } // Retain original mask at the very least for (size_t y = 0; y < height; y++) { @@ -170,6 +186,17 @@ uint16_t* closeup(uint16_t* mask, uint32_t width, uint32_t height, size_t num_pi return new_mask; } +// Close up masks by N-pixels +// Update pointer +void closeup(uint16_t** mask, uint32_t width, uint32_t height, size_t num_pixels) +{ + uint16_t *new_mask = _closeup(*mask, width, height, num_pixels); + if (new_mask != NULL) { + free(*mask); + *mask = new_mask; + } +} + // Combine Label Masks // For all empty spaces in the destination, put the extra label if it exists // Allocates an array if destination is unallocated @@ -290,3 +317,41 @@ struct bitmap_t* uint16_to_bitmap(uint16_t* buffer, uint32_t width, uint32_t hei bitmap->height = (size_t)height; return bitmap; } + +// Reduce a mask to the contiguous regions +uint16_t* _reduce_contiguous_regions(uint16_t* masks, uint32_t width, uint32_t height, uint16_t* total_labels) +{ + uint16_t starting_label = 1; + uint16_t* new_masks = (uint16_t*)calloc(width*height, sizeof(uint16_t)); + if (new_masks == NULL) { + return NULL; + } + for (size_t y = 0; y < height; y++) { + for (size_t x = 0; x < width; x++) { + size_t coord = x + y*width; + uint8_t channels = 2; // uint16_t = 2*uint8_t + if (flood((uint8_t*)masks, new_masks, width, height, channels, x, y, &(((uint8_t*)masks)[coord*channels]), starting_label)) { + starting_label++; + } + } + } + if (total_labels != NULL) { + *total_labels = starting_label; + } + return new_masks; +} + +// Reduce a mask to the contiguous regions +// Automatically update pointer to contiguous mask +// Freeing previous mask +void reduce_contiguous_regions(uint16_t** masks_p, uint32_t width, uint32_t height, uint16_t* total_labels) +{ + if (masks_p == NULL) { + return; + } + uint16_t* new_masks = _reduce_contiguous_regions(*masks_p, width, height, total_labels); + if (new_masks != NULL) { + free(*masks_p); + *masks_p = new_masks; + } +} @@ -133,110 +133,28 @@ int main(int argc, char** argv) return 1; } + uint16_t* new_masks; // Regenerate contiguous labels - starting_label = 1; - uint16_t* labels = (uint16_t*)calloc(width*height, sizeof(uint16_t)); - if (labels == NULL) { - fprintf(stderr, "Memory allocation error\n"); - free(masks); - } - for (size_t y = 0; y < height; y++) { - for (size_t x = 0; x < width; x++) { - size_t coord = x + y*width; - uint8_t channels = 2; - if (flood((uint8_t*)masks, labels, width, height, channels, x, y, &(((uint8_t*)masks)[coord*channels]), starting_label)) { - starting_label++; - } - } - } - uint16_t *temp = labels; - labels = masks; - masks = temp; - free(labels); + reduce_contiguous_regions(&masks, width, height, &starting_label); if (!silent) { printf("%u labels found\n", starting_label-1); printf("Mask dimensions: %u %u\n", width, height); } - // Get the area/ perimeter of each label - root = NULL; - TIME(ts_info_start); - for (size_t y = 0; y < height; y++) { - for (size_t x = 0; x < width; x++) { - if (masks[x + y*width] != 0) { - root = increase_label_area_alloc(root, masks[x + y*width]); - if (is_on_mask_boundary(masks, width, height, x, y)) { - increase_label_perimeter(root, masks[x + y*width]); - } - } - } - } - TIME(ts_info_end); - if (!silent) { - printf("Information retrieval took %f ms\n", 1000*diff_time(&ts_info_end, &ts_info_start)); - } -#ifdef AVL_INFO - if (!silent) { - printf("Inorder traversal of AVL tree: "); - print_label(root); - printf("\n"); - } -#endif TIME(ts_filter_start); - // Get the smallest labels - struct AVLNode* small_label_tree = NULL; - small_label_tree = get_small_labels(NULL, root, MIN_AREA, MIN_PERIMETER); - - // Remove the small labels - for (size_t y = 0; y < height; y++) { - for (size_t x = 0; x < width; x++) { - if (in_uint16_t_tree(small_label_tree, masks[x + y*width])) { - masks[x + y*width] = 0; - } - } - } + filter_small_masks(masks, width, height, MIN_AREA, MIN_PERIMETER); TIME(ts_filter_end); if (!silent) { printf("Removing small labels took %f ms\n", 1000*diff_time(&ts_filter_end, &ts_filter_start)); } - free_avl_tree(small_label_tree); - free_avl_tree_nodes(root); // Regenerate contiguous labels - starting_label = 1; - labels = (uint16_t*)calloc(width*height, sizeof(uint16_t)); - if (labels == NULL) { - fprintf(stderr, "Memory allocation error\n"); - free(masks); - } - for (size_t y = 0; y < height; y++) { - for (size_t x = 0; x < width; x++) { - size_t coord = x + y*width; - uint8_t channels = 2; - if (flood((uint8_t*)masks, labels, width, height, channels, x, y, &(((uint8_t*)masks)[coord*channels]), starting_label)) { - starting_label++; - } - } - } - temp = labels; - labels = masks; - masks = temp; - free(labels); + reduce_contiguous_regions(&masks, width, height, &starting_label); if (!silent) { printf("%u remaining labels found\n", starting_label-1); printf("Mask dimensions: %u %u\n", width, height); } // Regenerate information after relabeling - root = NULL; - for (size_t y = 0; y < height; y++) { - for (size_t x = 0; x < width; x++) { - if (masks[x + y*width] != 0) { - root = increase_label_area_alloc(root, masks[x + y*width]); - if (is_on_mask_boundary(masks, width, height, x, y)) { - increase_label_perimeter(root, masks[x + y*width]); - } - } - } - } + root = get_mask_data(masks, width, height); #ifdef AVL_INFO if (!silent) { printf("Inorder traversal of AVL tree: "); @@ -248,11 +166,7 @@ int main(int argc, char** argv) uint16_t *new_labels; TIME(ts_start); - new_labels = closeup(masks, width, height, N_DILATIONS); - if (new_labels != NULL) { - free(masks); - masks = new_labels; - } + closeup(&masks, width, height, N_DILATIONS); TIME(ts_end); if (!silent) { printf("Closing up took %f ms\n", 1000*diff_time(&ts_end, &ts_start)); |