diff options
-rw-r--r-- | Makefile | 98 | ||||
-rw-r--r-- | include/lib/color.h | 4 | ||||
-rw-r--r-- | include/lib/monad.h | 2 | ||||
-rw-r--r-- | include/lib/time.h | 2 | ||||
-rw-r--r-- | include/test/__meta__.h | 19 | ||||
-rw-r--r-- | include/test/lib/color.h | 17 | ||||
-rw-r--r-- | include/test/lib/dir.h | 18 | ||||
-rw-r--r-- | include/test/lib/time.h | 16 | ||||
-rw-r--r-- | lib/algo/avl_tree.c (renamed from src/lib/algo/avl_tree.c) | 0 | ||||
-rw-r--r-- | lib/algo/flood_fill.c (renamed from src/lib/algo/flood_fill.c) | 0 | ||||
-rw-r--r-- | lib/color.c (renamed from src/lib/color.c) | 4 | ||||
-rw-r--r-- | lib/dir.c (renamed from src/lib/dir.c) | 0 | ||||
-rw-r--r-- | lib/file.c (renamed from src/lib/file.c) | 0 | ||||
-rw-r--r-- | lib/lib.c (renamed from src/lib/lib.c) | 0 | ||||
-rw-r--r-- | lib/png.c (renamed from src/lib/png.c) | 0 | ||||
-rw-r--r-- | lib/seg/mask_data.c (renamed from src/lib/seg/mask_data.c) | 0 | ||||
-rw-r--r-- | lib/seg/util.c (renamed from src/lib/seg/util.c) | 21 | ||||
-rw-r--r-- | lib/time.c (renamed from src/lib/time.c) | 2 | ||||
-rwxr-xr-x | run.sh | 2 | ||||
-rw-r--r-- | src/prog.c | 214 | ||||
-rw-r--r-- | src/visual.c (renamed from src/main.c) | 34 | ||||
-rw-r--r-- | test/lib/color.c | 175 | ||||
-rw-r--r-- | test/lib/dir.c | 95 | ||||
-rw-r--r-- | test/lib/time.c | 61 | ||||
-rw-r--r-- | test/test.c | 30 |
25 files changed, 767 insertions, 47 deletions
@@ -1,15 +1,63 @@ PKGS=libtiff-4 libpng -#PKGS+=raylib -EXE=prog +DEFINES= BUILD_DIR=build/ -OBJ_DIR=$(BUILD_DIR)obj/ -SRC_DIR=src/ INC_DIR=include/ -SRCS=$(shell find $(SRC_DIR) -iname \*.c) -OBJS_sub=$(subst $(SRC_DIR),$(OBJ_DIR),$(SRCS)) -OBJS=$(OBJS_sub:.c=.o) -OBJ_DIRS_sub=$(shell find $(SRC_DIR) -type d) -OBJ_DIRS=$(subst $(SRC_DIR),$(OBJ_DIR),$(OBJ_DIRS_sub)) + +# Source files +SRC_DIR=src/ +SRC_OBJ_DIR=$(BUILD_DIR)obj/$(SRC_DIR) +SRC_SRCS=$(shell find $(SRC_DIR) -iname \*.c) +SRC_OBJS_sub=$(subst $(SRC_DIR),$(SRC_OBJ_DIR),$(SRC_SRCS)) +SRC_OBJS=$(SRC_OBJS_sub:.c=.o) +SRC_OBJ_DIRS_sub=$(shell find $(SRC_DIR) -type d) +SRC_OBJ_DIRS=$(subst $(SRC_DIR),$(SRC_OBJ_DIR),$(SRC_OBJ_DIRS_sub)) + +# Library files +LIB_DIR=lib/ +LIB_OBJ_DIR=$(BUILD_DIR)obj/$(LIB_DIR) +LIB_SRCS=$(shell find $(LIB_DIR) -iname \*.c) +LIB_OBJS_sub=$(subst $(LIB_DIR),$(LIB_OBJ_DIR),$(LIB_SRCS)) +LIB_OBJS=$(LIB_OBJS_sub:.c=.o) +LIB_OBJ_DIRS_sub=$(shell find $(LIB_DIR) -type d) +LIB_OBJ_DIRS=$(subst $(LIB_DIR),$(LIB_OBJ_DIR),$(LIB_OBJ_DIRS_sub)) + +# Library files +TEST_DIR=test/ +TEST_OBJ_DIR=$(BUILD_DIR)obj/$(TEST_DIR) +TEST_SRCS=$(shell find $(TEST_DIR) -iname \*.c) +TEST_OBJS_sub=$(subst $(TEST_DIR),$(TEST_OBJ_DIR),$(TEST_SRCS)) +TEST_OBJS=$(TEST_OBJS_sub:.c=.o) +TEST_OBJ_DIRS_sub=$(shell find $(TEST_DIR) -type d) +TEST_OBJ_DIRS=$(subst $(TEST_DIR),$(TEST_OBJ_DIR),$(TEST_OBJ_DIRS_sub)) + +# Programs +PROG_DIR= +PROG_OUT_DIR=$(BUILD_DIR)$(PROG_DIR) +PROG_SRCS=$(shell find $(SRC_DIR) -iname \*.c) +PROG_OBJS=$(PROG_SRCS:.c=.o) +PROG_DIRS_sub=$(shell find $(SRC_DIR) -type d) +PROG_DIRS=$(subst $(SRC_DIR),$(PROG_OUT_DIR),$(PROG_DIRS_sub)) +PROGS_sub=$(subst $(SRC_DIR),$(PROG_OUT_DIR),$(PROG_SRCS)) +PROGS=$(PROGS_sub:.c=) + +# Include raylib if we want a visual experience +ifdef RAYLIB +$(info Visual Experience Selected) +PKGS+=raylib +DEFINES+=-DVISUAL +endif + +# Dump AVL tree info? +ifdef AVL_INFO +$(info Including AVL Dump) +DEFINES+=-DAVL_INFO +endif + +# Suppress Test Passings +ifdef TEST_SHOW_PASS +$(info Showing test pass results) +DEFINES+=-DTEST_SHOW_PASS +endif ifeq ($(shell uname -s),Linux) PKGCONF=pkgconf @@ -21,29 +69,43 @@ endif CFLAGS= CFLAGS+=$(shell $(PKGCONF) --cflags $(PKGS)) CFLAGS+=-I$(INC_DIR) +CFLAGS+=$(DEFINES) +CFLAGS+=-Wall LDFLAGS= LDFLAGS+=$(shell $(PKGCONF) --libs $(PKGS)) default: clean build -.PHONY: clean build run +.PHONY: clean build test run -build: $(BUILD_DIR)$(EXE) +build: $(PROGS) -$(BUILD_DIR)$(EXE): $(OBJS) +$(BUILD_DIR)$(PROG_DIR)%: $(SRC_OBJ_DIR)%.o $(LIB_OBJS) @echo LD --\> $@ @gcc -o $@ $(LDFLAGS) $^ -$(OBJ_DIR)%.o: $(SRC_DIR)%.c +build/test: $(TEST_OBJS) $(LIB_OBJS) + @echo LD --\> $@ + @gcc -o $@ $(LDFLAGS) $^ + +$(SRC_OBJ_DIR)%.o: $(SRC_DIR)%.c + @echo CC $< --\> $@ + @gcc -o $@ $(CFLAGS) -c $< + +$(LIB_OBJ_DIR)%.o: $(LIB_DIR)%.c @echo CC $< --\> $@ @gcc -o $@ $(CFLAGS) -c $< +$(TEST_OBJ_DIR)%.o: $(TEST_DIR)%.c + @echo CC $< --\> $@ + @gcc -o $@ $(CFLAGS) -c $< + +test: clean build/test + @echo Test beginning... + @./build/test + clean: @echo Cleaning build files... @-rm -rf $(OBJ_DIR) $(BUILD_DIR) - @mkdir -p $(OBJ_DIR) $(BUILD_DIR) $(OBJ_DIRS) - -run: $(BUILD_DIR)$(EXE) - @echo Executing... - @./$(BUILD_DIR)$(EXE) + @mkdir -p $(BUILD_DIR) $(SRC_OBJ_DIRS) $(LIB_OBJ_DIRS) $(TEST_OBJ_DIRS) $(PROG_DIRS) diff --git a/include/lib/color.h b/include/lib/color.h index 5e7128b..1bc9393 100644 --- a/include/lib/color.h +++ b/include/lib/color.h @@ -7,11 +7,11 @@ // Color Equal to Background // Background: zeros in RGB, alpha can be whatever -bool_t color_zero(uint8_t* color1, size_t channels); +bool_t color_zero(const uint8_t* color1, size_t channels); // Color Equality // Determine if two colors are identical -bool_t color_equal(uint8_t* color1, uint8_t* color2, size_t channels); +bool_t color_equal(const uint8_t* color1, const uint8_t* color2, size_t channels); // Print out the `channels` length color vector void print_color(uint8_t* color, size_t channels); diff --git a/include/lib/monad.h b/include/lib/monad.h index 4a68e0a..74db079 100644 --- a/include/lib/monad.h +++ b/include/lib/monad.h @@ -1,6 +1,8 @@ #ifndef INC_LIB_MONAD_H #define INC_LIB_MONAD_H +#include <lib/bool.h> + struct Result { void* data; bool_t success; diff --git a/include/lib/time.h b/include/lib/time.h index 9d69b44..1adf428 100644 --- a/include/lib/time.h +++ b/include/lib/time.h @@ -7,7 +7,7 @@ // Difference in Time // Compute the difference between timespec structs -double diff_time(struct timespec *time1, struct timespec *time0); +double diff_time(const struct timespec *time1, const struct timespec *time0); // Get Current Time void get_time(struct timespec *ts); diff --git a/include/test/__meta__.h b/include/test/__meta__.h new file mode 100644 index 0000000..305698a --- /dev/null +++ b/include/test/__meta__.h @@ -0,0 +1,19 @@ +#ifndef INC_TEST___META___H +#define INC_TEST___META___H + +#include <lib/bool.h> +#include <stdio.h> + +#ifdef TEST_SHOW_PASS +#define _TEST_PASS(s,sub,n) fprintf(stderr, "(%4X) \x1b[92mPASS\x1b[0m %s/%s\n", ++n, s, sub) +#else +#define _TEST_PASS(s,sub,n) ++n +#endif + +#define _TEST_FAIL(s,sub,n) fprintf(stderr, "(%4X) \x1b[91mFAIL\x1b[0m %s/%s\n", ++n, s, sub) + +#ifndef _TEST_RESULT +#define _TEST_RESULT(main_string,subtest_string,result,n,n_success) if (!result) {_TEST_FAIL(main_string,subtest_string, n);} else {_TEST_PASS(main_string,subtest_string,n);n_success++;} +#endif + +#endif diff --git a/include/test/lib/color.h b/include/test/lib/color.h new file mode 100644 index 0000000..be0d62f --- /dev/null +++ b/include/test/lib/color.h @@ -0,0 +1,17 @@ +#ifndef INC_TEST_LIB_COLOR_H +#define INC_TEST_LIB_COLOR_H + +#include <test/__meta__.h> +#ifndef TEST_RESULT +#define TEST_RESULT(subtest,result,n,n_success) _TEST_RESULT("LIB/COLOR",subtest,result,n,n_success) +#endif + +#include <lib/color.h> + +bool_t test_color_zero(const uint8_t* color1, size_t channels, bool_t result); +bool_t test_color_equal(const uint8_t* color1, const uint8_t* color2, size_t channels, bool_t result); + +// Meta test function +bool_t TEST_lib_color(); + +#endif diff --git a/include/test/lib/dir.h b/include/test/lib/dir.h new file mode 100644 index 0000000..64482df --- /dev/null +++ b/include/test/lib/dir.h @@ -0,0 +1,18 @@ +#ifndef INC_TEST_LIB_DIR_H +#define INC_TEST_LIB_DIR_H + +#include <test/__meta__.h> +#ifndef TEST_RESULT +#define TEST_RESULT(subtest,result,n,n_success) _TEST_RESULT("LIB/DIR",subtest,result,n,n_success) +#endif + +#include <lib/dir.h> + +bool_t test_is_directory(char* dirname, bool_t result); +bool_t test_full_path(char* dirname, char* file, char* result); +bool_t test_is_tif_ext(char* file_name, bool_t result); + +// Meta test function +bool_t TEST_lib_dir(); + +#endif diff --git a/include/test/lib/time.h b/include/test/lib/time.h new file mode 100644 index 0000000..cdf464e --- /dev/null +++ b/include/test/lib/time.h @@ -0,0 +1,16 @@ +#ifndef INC_TEST_LIB_TIME_H +#define INC_TEST_LIB_TIME_H + +#include <test/__meta__.h> +#ifndef TEST_RESULT +#define TEST_RESULT(subtest,result,n,n_success) _TEST_RESULT("LIB/TIME",subtest,result,n,n_success) +#endif + +#include <lib/time.h> + +bool_t test_diff_time(const struct timespec *time1, const struct timespec *time0, double result); + +// Meta test function +bool_t TEST_lib_time(); + +#endif diff --git a/src/lib/algo/avl_tree.c b/lib/algo/avl_tree.c index db4fa4b..db4fa4b 100644 --- a/src/lib/algo/avl_tree.c +++ b/lib/algo/avl_tree.c diff --git a/src/lib/algo/flood_fill.c b/lib/algo/flood_fill.c index 62db658..62db658 100644 --- a/src/lib/algo/flood_fill.c +++ b/lib/algo/flood_fill.c diff --git a/src/lib/color.c b/lib/color.c index 902a93d..a0a50fd 100644 --- a/src/lib/color.c +++ b/lib/color.c @@ -4,7 +4,7 @@ // Color Equal to Background // Background: zeros in RGB, alpha can be whatever -bool_t color_zero(uint8_t* color1, size_t channels) { +bool_t color_zero(const uint8_t* color1, size_t channels) { for (size_t idx = 0; idx < channels; idx++) { if (idx == 3) { break; @@ -18,7 +18,7 @@ bool_t color_zero(uint8_t* color1, size_t channels) { // Color Equality // Determine if two colors are identical -bool_t color_equal(uint8_t* color1, uint8_t* color2, size_t channels) { +bool_t color_equal(const uint8_t* color1, const uint8_t* color2, size_t channels) { for (size_t idx = 0; idx < channels; idx++) { if (color1[idx] != color2[idx]) { return FALSE; diff --git a/src/lib/dir.c b/lib/dir.c index be2a2ac..be2a2ac 100644 --- a/src/lib/dir.c +++ b/lib/dir.c diff --git a/src/lib/file.c b/lib/file.c index b6ec1d0..b6ec1d0 100644 --- a/src/lib/file.c +++ b/lib/file.c diff --git a/src/lib/lib.c b/lib/lib.c index c1f26fc..c1f26fc 100644 --- a/src/lib/lib.c +++ b/lib/lib.c diff --git a/src/lib/png.c b/lib/png.c index d12a765..d12a765 100644 --- a/src/lib/png.c +++ b/lib/png.c diff --git a/src/lib/seg/mask_data.c b/lib/seg/mask_data.c index 8c4b037..8c4b037 100644 --- a/src/lib/seg/mask_data.c +++ b/lib/seg/mask_data.c diff --git a/src/lib/seg/util.c b/lib/seg/util.c index a45f6c8..677e8f5 100644 --- a/src/lib/seg/util.c +++ b/lib/seg/util.c @@ -7,6 +7,12 @@ #include <stdlib.h> #include <string.h> +// Suppress Tiff Warnings +void TiffDummyHandler(const char* module, const char* fmt, va_list ap) +{ + // ignore errors and warnings (or handle them your own way) +} + // Convert x,y coords to linear coordinate size_t xy_to_coord(size_t x, size_t y, uint32_t width, uint32_t height) { @@ -109,40 +115,36 @@ void dilate(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)); + memcpy(new_mask, mask, width*height*sizeof(uint16_t)); for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { size_t current_position = xy_to_coord(x, y, width, height); - if (mask[current_position] != 0) { - new_mask[current_position] = mask[current_position]; - continue; - } - bool_t erode = FALSE; size_t proposed_position; if (x != 0) { proposed_position = xy_to_coord(x-1, y, width, height); if (mask[proposed_position] == 0) { - new_mask[current_position] = mask[proposed_position]; + new_mask[current_position] = 0; continue; } } if ((x+1) != width) { proposed_position = xy_to_coord(x+1, y, width, height); if (mask[proposed_position] == 0) { - new_mask[current_position] = mask[proposed_position]; + new_mask[current_position] = 0; continue; } } if (y != 0) { proposed_position = xy_to_coord(x, y-1, width, height); if (mask[proposed_position] == 0) { - new_mask[current_position] = mask[proposed_position]; + new_mask[current_position] = 0; continue; } } if ((y+1) != height) { proposed_position = xy_to_coord(x, y+1, width, height); if (mask[proposed_position] == 0) { - new_mask[current_position] = mask[proposed_position]; + new_mask[current_position] = 0; continue; } } @@ -221,6 +223,7 @@ uint16_t* combine_masks(uint16_t *destination, uint16_t *extra_labels, uint32_t // starting_label_p will be incremented for each label found in the image uint16_t* tif_to_labels(char* tif_file_name, uint32_t *width, uint32_t *height, uint16_t *starting_label_p) { + TIFFSetWarningHandler(TiffDummyHandler); //-TIFF-IMAGE-OPEN------------------------------- TIFF *tif = TIFFOpen(tif_file_name, "r"); if (!tif) { diff --git a/src/lib/time.c b/lib/time.c index 085ef80..623a696 100644 --- a/src/lib/time.c +++ b/lib/time.c @@ -2,7 +2,7 @@ // Difference in Time // Compute the difference between timespec structs -double diff_time(struct timespec *time1, struct timespec *time0) { +double diff_time(const struct timespec *time1, const struct timespec *time0) { return (time1->tv_sec - time0->tv_sec) + (time1->tv_nsec - time0->tv_nsec) / 1000000000.0; } @@ -1,4 +1,4 @@ #!/bin/sh SOURCE="$1" mkdir -p output/${SOURCE} -./build/prog -s -d data/${SOURCE} -b output/${SOURCE}/${SOURCE}.bin -p output/${SOURCE}/${SOURCE}.png +./build/prog -s -n 8 -d data/${SOURCE} -b output/${SOURCE}/${SOURCE}.bin -p output/${SOURCE}/${SOURCE}.png diff --git a/src/prog.c b/src/prog.c new file mode 100644 index 0000000..f23da54 --- /dev/null +++ b/src/prog.c @@ -0,0 +1,214 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <lib/lib.h> +#include <lib/png.h> +#include <lib/bool.h> +#include <lib/monad.h> +#include <lib/dir.h> +#include <lib/file.h> +#include <lib/time.h> +#include <lib/color.h> +#include <lib/algo/flood_fill.h> +#include <lib/algo/avl_tree.h> +#include <lib/seg/util.h> +#include <lib/seg/mask_data.h> + +int main(int argc, char** argv) +{ + char opt; + char* directory = NULL; + char* png_file = "../out.png"; + char* bin_file = "../out.bin"; + size_t closeup_pixel_count = 10; + size_t min_area = 500; + size_t min_perimeter = 0; + bool_t silent = FALSE; + //----------------------------------------------- + //-GET-COMMAND-LINE-ARGUMENTS-------------------- + //----------------------------------------------- + while ((opt = getopt(argc, argv, "d:b:p:n:sA:P:")) != -1) { + switch (opt) { + case 's': + silent = TRUE; + break; + case 'A': + min_area = atoi(optarg); + break; + case 'P': + min_perimeter = atoi(optarg); + break; + case 'd': + if (!silent) { + printf("Parse Directory: %s\n", optarg); + } + directory = optarg; + break; + case 'b': + if (!silent) { + printf("Bin File: %s\n", optarg); + } + bin_file = optarg; + break; + case 'p': + if (!silent) { + printf("PNG File: %s\n", optarg); + } + png_file = optarg; + break; + case 'n': + if (!silent) { + printf("Closeup Size: %d\n", atoi(optarg)); + } + closeup_pixel_count = atoi(optarg); + break; + case ':': + if (!silent) { + printf("Option requires value\n"); + } + break; + case '?': + if (!silent) { + printf("Unknown option: %c\n", optopt); + } + break; + } + } + if (!silent) { + for (;optind < argc; optind++) { + printf("Extra arguments: %s\n", argv[optind]); + } + } + TIME(ts_g_start); + //----------------------------------------------- + //-PROCESS-FILES-IN-DIRECTORY-------------------- + //----------------------------------------------- + char** file_list = NULL; + uint32_t width, height; + uint16_t starting_label = 1; + uint16_t *masks = NULL; + // Expect a directory to be passed as the first argument + if (directory != NULL) { + // Ensure the directory exists + if (is_directory(directory)) { + // List files in the ddirectory + file_list = list_directory(directory); + if (file_list != NULL) { + for (size_t index = 0; file_list[index] != NULL; index++) { + char* fname = file_list[index]; + if (is_tif_ext(fname) == FALSE) { + free(file_list[index]); + continue; + } + // If we have a tiff file + // 1. Convert to labels + // 2. Find contiguous regions + // 3. Combine with current total mask + // 4. Free up allocations made in this process + char* fpath = full_path(directory, fname); + if (fpath == NULL) { + free(file_list[index]); + continue; + } + if (!silent) { + printf("Loading %s...\n", fpath); + } + //----------------------------------------------- + //-PROCESS-TIFF-TO-LABELS------------------------ + //----------------------------------------------- + uint16_t *file_labels = tif_to_labels(fpath, &width, &height, &starting_label); + if (file_labels == NULL) { + free(fpath); + free(file_list[index]); + continue; + } + //----------------------------------------------- + //-COMBINE-LABELS-TO-GLOBAL-MASK----------------- + //----------------------------------------------- + masks = combine_masks(masks, file_labels, width, height); + free(file_labels); + free(fpath); + free(file_list[index]); + } + free(file_list); + } + } + } + if (masks == NULL) { + fprintf(stderr, "No masks found!\n"); + return 1; + } + + //----------------------------------------------- + //-FIND-CONTIGUOUS-REGIONS----------------------- + //----------------------------------------------- + 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); + } + //----------------------------------------------- + //-FILTER-SMALL-REGIONS-OUT---------------------- + //----------------------------------------------- + TIME(ts_filter_start); + 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)); + } + //----------------------------------------------- + //-FIND-CONTIGUOUS-REGIONS----------------------- + //----------------------------------------------- + //--to-make-labels-span-1-to-n------------------- + //----------------------------------------------- + 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); + } +#ifdef AVL_INFO + //----------------------------------------------- + //-OPTIONAL:------------------------------------- + //-GET-MASK-META-INFORMATION--------------------- + //----------------------------------------------- + struct AVLNode* root = NULL; + root = get_mask_data(masks, width, height); + if (!silent) { + printf("Inorder traversal of AVL tree: "); + print_label(root); + printf("\n"); + } + free_avl_tree_nodes(root); +#endif + //----------------------------------------------- + //-CLOSE-UP-SMALL-GAPS-BETWEEN-REGIONS----------- + //----------------------------------------------- + TIME(ts_start); + closeup(&masks, width, height, closeup_pixel_count); + TIME(ts_end); + if (!silent) { + printf("Closing (%lu) up took %f ms\n", closeup_pixel_count, 1000*diff_time(&ts_end, &ts_start)); + } + //----------------------------------------------- + //-END-OF-PROCESSING----------------------------- + //----------------------------------------------- + + //----------------------------------------------- + //-SAVE-MASK-AS-BINARY-AND-PNG------------------- + //----------------------------------------------- + if (masks != NULL) { + struct bitmap_t* bitmap = uint16_to_bitmap(masks, width, height); + if (bitmap != NULL) { + save_png(bitmap, png_file); + free(bitmap); + } + write_array(bin_file, masks, width*height*sizeof(uint16_t)); + free(masks); + } + TIME(ts_g_end); + if (!silent) { + printf("Finished in %f ms\n", 1000*diff_time(&ts_g_end, &ts_g_start)); + } + return 0; +} diff --git a/src/main.c b/src/visual.c index fdabaf5..ac6f63d 100644 --- a/src/main.c +++ b/src/visual.c @@ -21,8 +21,6 @@ #define OFFSET 16 -#define N_DILATIONS 10 - #define MIN_AREA 500 #define MIN_PERIMETER 0 @@ -32,11 +30,12 @@ int main(int argc, char** argv) char* directory = NULL; char* png_file = "../out.png"; char* bin_file = "../out.bin"; + size_t closeup_pixel_count = 10; bool_t silent = FALSE; //----------------------------------------------- //-GET-COMMAND-LINE-ARGUMENTS-------------------- //----------------------------------------------- - while ((opt = getopt(argc, argv, "d:b:p:s")) != -1) { + while ((opt = getopt(argc, argv, "d:b:p:n:s")) != -1) { switch (opt) { case 's': silent = TRUE; @@ -59,6 +58,12 @@ int main(int argc, char** argv) } png_file = optarg; break; + case 'n': + if (!silent) { + printf("Closeup Size: %d\n", atoi(optarg)); + } + closeup_pixel_count = atoi(optarg); + break; case ':': if (!silent) { printf("Option requires value\n"); @@ -77,7 +82,6 @@ int main(int argc, char** argv) } } TIME(ts_g_start); - struct AVLNode* root = NULL; //----------------------------------------------- //-PROCESS-FILES-IN-DIRECTORY-------------------- //----------------------------------------------- @@ -111,12 +115,18 @@ int main(int argc, char** argv) if (!silent) { printf("Loading %s...\n", fpath); } + //----------------------------------------------- + //-PROCESS-TIFF-TO-LABELS------------------------ + //----------------------------------------------- uint16_t *file_labels = tif_to_labels(fpath, &width, &height, &starting_label); if (file_labels == NULL) { free(fpath); free(file_list[index]); continue; } + //----------------------------------------------- + //-COMBINE-LABELS-TO-GLOBAL-MASK----------------- + //----------------------------------------------- masks = combine_masks(masks, file_labels, width, height); free(file_labels); free(fpath); @@ -131,7 +141,6 @@ int main(int argc, char** argv) return 1; } - uint16_t* new_masks; //----------------------------------------------- //-FIND-CONTIGUOUS-REGIONS----------------------- //----------------------------------------------- @@ -140,10 +149,10 @@ int main(int argc, char** argv) printf("%u labels found\n", starting_label-1); printf("Mask dimensions: %u %u\n", width, height); } - TIME(ts_filter_start); //----------------------------------------------- //-FILTER-SMALL-REGIONS-OUT---------------------- //----------------------------------------------- + TIME(ts_filter_start); filter_small_masks(masks, width, height, MIN_AREA, MIN_PERIMETER); TIME(ts_filter_end); if (!silent) { @@ -159,29 +168,28 @@ int main(int argc, char** argv) printf("%u remaining labels found\n", starting_label-1); printf("Mask dimensions: %u %u\n", width, height); } +#ifdef AVL_INFO //----------------------------------------------- //-OPTIONAL:------------------------------------- //-GET-MASK-META-INFORMATION--------------------- //----------------------------------------------- + struct AVLNode* root = NULL; root = get_mask_data(masks, width, height); -#ifdef AVL_INFO if (!silent) { printf("Inorder traversal of AVL tree: "); print_label(root); printf("\n"); } -#endif free_avl_tree_nodes(root); - - uint16_t *new_labels; - TIME(ts_start); +#endif //----------------------------------------------- //-CLOSE-UP-SMALL-GAPS-BETWEEN-REGIONS----------- //----------------------------------------------- - closeup(&masks, width, height, N_DILATIONS); + TIME(ts_start); + closeup(&masks, width, height, closeup_pixel_count); TIME(ts_end); if (!silent) { - printf("Closing up took %f ms\n", 1000*diff_time(&ts_end, &ts_start)); + printf("Closing (%lu) up took %f ms\n", closeup_pixel_count, 1000*diff_time(&ts_end, &ts_start)); } //----------------------------------------------- //-END-OF-PROCESSING----------------------------- diff --git a/test/lib/color.c b/test/lib/color.c new file mode 100644 index 0000000..69ce97b --- /dev/null +++ b/test/lib/color.c @@ -0,0 +1,175 @@ +#include <test/lib/color.h> + +const uint8_t test_rgba[4] = {0,0,0,0}; +const uint8_t test_Rgba[4] = {1,0,0,0}; +const uint8_t test_rGba[4] = {0,1,0,0}; +const uint8_t test_rgBa[4] = {0,0,1,0}; +const uint8_t test_rgbA[4] = {0,0,0,1}; + +bool_t test_color_zero(const uint8_t* color1, size_t channels, bool_t result) +{ + bool_t fcall_result = color_zero(color1, channels); + if (fcall_result == result) { + return TRUE; + } + return FALSE; +} + +void _TEST_color_zero(bool_t* result, uint16_t* test_count, uint16_t* test_pass) +{ + bool_t sub_result; + // Test 1: 1 channel zero color + // Should result: True + sub_result = test_color_zero(test_rgba, 1, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 2: 1 channel non-zero color + // Should result: False + sub_result = test_color_zero(test_Rgba, 1, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 3: 2 channel zero color + // Should result: True + sub_result = test_color_zero(test_rgba, 2, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 4: 2 channel non-zero color + // Should result: False + sub_result = test_color_zero(test_rGba, 2, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 5: 3 channel zero color + // Should result: True + sub_result = test_color_zero(test_rgba, 3, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 6: 3 channel non-zero color + // Should result: False + sub_result = test_color_zero(test_rgBa, 3, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 7: 4 channel zero color + // Should result: True + sub_result = test_color_zero(test_rgba, 4, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 8: 4 channel non-zero color + // Should result: False + sub_result = test_color_zero(test_rgBa, 4, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); + + // Test 9: 4 channel non-zero color (Alpha non-zero) + // Should result: True + sub_result = test_color_zero(test_rgbA, 4, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_ZERO",sub_result, *test_count, (*test_pass)); +} + +bool_t test_color_equal(const uint8_t* color1, const uint8_t* color2, size_t channels, bool_t result) +{ + bool_t fcall_result = color_equal(color1, color2, channels); + if (fcall_result == result) { + return TRUE; + } + return FALSE; +} + +void _TEST_color_equal(bool_t* result, uint16_t* test_count, uint16_t* test_pass) +{ + bool_t sub_result; + // Test 1: 1 channel equal (zero) + // Should result: True + sub_result = test_color_equal(test_rgba, test_rgba, 1, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 2: 1 channel equal (nonzero) + // Should result: True + sub_result = test_color_equal(test_Rgba, test_Rgba, 1, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 3: 1 channel nonequal + // Should result: True + sub_result = test_color_equal(test_rgba, test_Rgba, 1, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 4: 2 channel equal (zero) + // Should result: True + sub_result = test_color_equal(test_rgba, test_rgba, 2, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 5: 2 channel equal (nonzero) + // Should result: True + sub_result = test_color_equal(test_rGba, test_rGba, 2, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 6: 2 channel nonequal + // Should result: False + sub_result = test_color_equal(test_Rgba, test_rGba, 2, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 7: 3 channel equal (zero) + // Should result: True + sub_result = test_color_equal(test_rgba, test_rgba, 3, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 8: 3 channel equal (nonzero) + // Should result: True + sub_result = test_color_equal(test_rgBa, test_rgBa, 3, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 9: 3 channel nonequal + // Should result: False + sub_result = test_color_equal(test_Rgba, test_rgBa, 3, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 7: 4 channel equal (zero) + // Should result: True + sub_result = test_color_equal(test_rgba, test_rgba, 4, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 8: 4 channel equal (nonzero) + // Should result: True + sub_result = test_color_equal(test_rgbA, test_rgbA, 4, TRUE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); + + // Test 9: 4 channel nonequal + // Should result: False + sub_result = test_color_equal(test_Rgba, test_rgbA, 4, FALSE); + *result &= sub_result; + TEST_RESULT("COLOR_EQUAL",sub_result, *test_count, (*test_pass)); +} + +// Meta test function +bool_t TEST_lib_color() +{ + uint16_t test_count = 0; + uint16_t test_pass = 0; + bool_t result = TRUE; + + // Testing color_zero + _TEST_color_zero(&result, &test_count, &test_pass); + + // Testing color_equal + _TEST_color_equal(&result, &test_count, &test_pass); + + return test_count == test_pass; +} diff --git a/test/lib/dir.c b/test/lib/dir.c new file mode 100644 index 0000000..66ce672 --- /dev/null +++ b/test/lib/dir.c @@ -0,0 +1,95 @@ +#include <test/lib/dir.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +bool_t test_is_directory(char* dirname, bool_t result) +{ + bool_t fcall_result = is_directory(dirname); + if (fcall_result == result) { + return TRUE; + } + return FALSE; +} + +void _TEST_is_directory(bool_t* result, uint16_t* test_count, uint16_t* test_pass) +{ + bool_t sub_result; + // Test 1: sample_data/ (TRUE) [On clean git folder] + sub_result = test_is_directory("sample_data", TRUE); + *result &= sub_result; + TEST_RESULT("IS_DIRECTORY",sub_result, *test_count, (*test_pass)); + + // Test 2: asdf/ (FALSE) [On clean git folder] + sub_result = test_is_directory("asdf", FALSE); + *result &= sub_result; + TEST_RESULT("IS_DIRECTORY",sub_result, *test_count, (*test_pass)); +} + +bool_t test_full_path(char* dirname, char* file, char* result) +{ + char* fpath = full_path(dirname, file); + bool_t cmp_result = strcmp(result, fpath); + free(fpath); + if (cmp_result == 0) { + return TRUE; + } + return FALSE; +} + +void _TEST_full_path(bool_t* result, uint16_t* test_count, uint16_t* test_pass) +{ + bool_t sub_result; + // Test 1: sample_data/small + small.tif = sample_data/small/small.tif + sub_result = test_full_path("sample_data/small", "small.tif", "sample_data/small/small.tif"); + *result &= sub_result; + TEST_RESULT("FULL_PATH",sub_result, *test_count, (*test_pass)); +} + +bool_t test_is_tif_ext(char* file_name, bool_t result) +{ + size_t file_name_len = strlen(file_name); + file_name_len -= 3; + bool_t cmp_result = strcmp(file_name+file_name_len, "tif"); + if (cmp_result == 0) { + return TRUE == result; + } + return FALSE == result; +} + +void _TEST_is_tif_ext(bool_t* result, uint16_t* test_count, uint16_t* test_pass) +{ + bool_t sub_result; + // Test 1: sample_data/small/small.tif (TRUE) + sub_result = test_is_tif_ext("sample_data/small/small.tif", TRUE); + *result &= sub_result; + TEST_RESULT("IS_TIF_EXT",sub_result, *test_count, (*test_pass)); + + // Test 2: data/test.tif (TRUE) + sub_result = test_is_tif_ext("data/test.tif", TRUE); + *result &= sub_result; + TEST_RESULT("IS_TIF_EXT",sub_result, *test_count, (*test_pass)); + + // Test 3: sample_data/small/small (FALSE) + sub_result = test_is_tif_ext("sample_data/small/small", FALSE); + *result &= sub_result; + TEST_RESULT("IS_TIF_EXT",sub_result, *test_count, (*test_pass)); +} + +bool_t TEST_lib_dir() +{ + uint16_t test_count = 0; + uint16_t test_pass = 0; + bool_t result = TRUE; + + // Testing directory existence + _TEST_is_directory(&result, &test_count, &test_pass); + + // Testing full path + _TEST_full_path(&result, &test_count, &test_pass); + + // Testing full path + _TEST_is_tif_ext(&result, &test_count, &test_pass); + + return test_count == test_pass; +} diff --git a/test/lib/time.c b/test/lib/time.c new file mode 100644 index 0000000..5c29bbc --- /dev/null +++ b/test/lib/time.c @@ -0,0 +1,61 @@ +#include <test/lib/time.h> + +const struct timespec zero = {0,0}; +const struct timespec one_s = {1,0}; +const struct timespec one_ns = {0,1}; +const struct timespec one_s_ns = {1,1}; + +bool_t test_diff_time(const struct timespec *time1, const struct timespec *time0, double result) +{ + double fcall_result = diff_time(time1, time0); + if (fcall_result == result) { + return TRUE; + } + return FALSE; +} + +void _TEST_diff_time(bool_t* result, uint16_t* test_count, uint16_t* test_pass) +{ + bool_t sub_result; + // Test 1: 0-0=0 + sub_result = test_diff_time(&zero, &zero, 0.0); + *result &= sub_result; + TEST_RESULT("DIFF_TIME",sub_result, *test_count, (*test_pass)); + + // Test 2: 1s-0=1s + sub_result = test_diff_time(&one_s, &zero, 1.0); + *result &= sub_result; + TEST_RESULT("DIFF_TIME",sub_result, *test_count, (*test_pass)); + + // Test 3: 1ns-0=1ns + sub_result = test_diff_time(&one_ns, &zero, 0.000000001); + *result &= sub_result; + TEST_RESULT("DIFF_TIME",sub_result, *test_count, (*test_pass)); + + // Test 4: 1s1ns-0=1s1ns + sub_result = test_diff_time(&one_s_ns, &zero, 1.000000001); + *result &= sub_result; + TEST_RESULT("DIFF_TIME",sub_result, *test_count, (*test_pass)); + + // Test 5: 1s1ns-1ns=1s + sub_result = test_diff_time(&one_s_ns, &one_ns, 1.0); + *result &= sub_result; + TEST_RESULT("DIFF_TIME",sub_result, *test_count, (*test_pass)); + + // Test 6: 1s1ns-1s=1ns + sub_result = test_diff_time(&one_s_ns, &one_s, 0.000000001); + *result &= sub_result; + TEST_RESULT("DIFF_TIME",sub_result, *test_count, (*test_pass)); +} + +bool_t TEST_lib_time() +{ + uint16_t test_count = 0; + uint16_t test_pass = 0; + bool_t result = TRUE; + + // Testing directory existence + _TEST_diff_time(&result, &test_count, &test_pass); + + return test_count == test_pass; +} diff --git a/test/test.c b/test/test.c new file mode 100644 index 0000000..40e2d6f --- /dev/null +++ b/test/test.c @@ -0,0 +1,30 @@ +#include <test/lib/color.h> +#include <test/lib/dir.h> +#include <test/lib/time.h> + +#define _META_TEST_RESULT(name,result) if (result) { fprintf(stderr, " \x1b[92mPASS\x1b[0m %s\n", name);} else { fprintf(stderr, "%s: \x1b[91mFAIL\x1b[0m\n", name);} + +int main() +{ + bool_t all_success = TRUE; + bool_t test_success; + // lib/color.c Test + test_success = TEST_lib_color(); + all_success &= test_success; + _META_TEST_RESULT("LIB/COLOR", test_success) + + // lib/dir.c Test + test_success = TEST_lib_dir(); + all_success &= test_success; + _META_TEST_RESULT("LIB/DIR", test_success) + + // lib/time.c Test + test_success = TEST_lib_time(); + all_success &= test_success; + _META_TEST_RESULT("LIB/TIME", test_success) + + if (all_success == TRUE) { + return 0; + } + return 1; +} |