aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/lib/seg/mask_data.h6
-rw-r--r--include/lib/seg/util.h11
-rw-r--r--src/lib/seg/mask_data.c37
-rw-r--r--src/lib/seg/util.c85
-rw-r--r--src/main.c98
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;
+ }
+}
diff --git a/src/main.c b/src/main.c
index 4d19dc3..a18d602 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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));