diff --git a/Sources/Extraction/Extract.c b/Sources/Extraction/Extract.c index 37c9976..bd22d16 100644 --- a/Sources/Extraction/Extract.c +++ b/Sources/Extraction/Extract.c @@ -9,10 +9,11 @@ #include "Extraction/Filters/OrientedSmoother.h" #include "Extraction/Filters/ThresholdBinarizer.h" #include "Extraction/Filters/Thinner.h" +#include "Templates/Template.h" const int blockSize = 16; -void Extract(UInt8Array2D *image, struct perfdata *perfdata, UInt8Array2D *outBinarized, UInt8Array2D *outThinned) +void Extract(UInt8Array2D *image, Template *template, struct perfdata *perfdata, UInt8Array2D *outBinarized, UInt8Array2D *outThinned) { if (perfdata) gettimeofday(&perfdata->start, 0); Size size = Size_Construct(image->sizeX, image->sizeY); @@ -71,9 +72,17 @@ void Extract(UInt8Array2D *image, struct perfdata *perfdata, UInt8Array2D *outBi // Minutiae detection if (perfdata) gettimeofday(&perfdata->start_detection, 0); + //TODO: wire-up minutiae detection. // Minutiae filtering if (perfdata) gettimeofday(&perfdata->start_filtering, 0); + //TODO: wire-up minutiae filtering. + + // Generate Template + if (perfdata) gettimeofday(&perfdata->start_template, 0); + //TODO: Generate Template from minutiae. + + if (perfdata) gettimeofday(&perfdata->end, 0); // Cleanup BlockMap_Destruct(&blocks); diff --git a/Sources/Extraction/Extract.h b/Sources/Extraction/Extract.h index f914bbf..a0590da 100644 --- a/Sources/Extraction/Extract.h +++ b/Sources/Extraction/Extract.h @@ -1,6 +1,7 @@ #include #include "General/Array.h" #include "General/BinaryMap.h" +#include "Templates/Template.h" struct perfdata { struct timeval start; @@ -12,7 +13,8 @@ struct perfdata { struct timeval start_thinning; struct timeval start_detection; struct timeval start_filtering; + struct timeval start_template; struct timeval end; -}; +} perfdata; -void Extract(UInt8Array2D *image, struct perfdata *perfdata, UInt8Array2D *binarized, UInt8Array2D *thinned); +void Extract(UInt8Array2D *image, Template *template, struct perfdata *perfdata, UInt8Array2D *binarized, UInt8Array2D *thinned); diff --git a/Sources/General/List.h b/Sources/General/List.h index 2a8c345..b3c5387 100644 --- a/Sources/General/List.h +++ b/Sources/General/List.h @@ -1,6 +1,6 @@ #ifndef GENERAL_LIST_H #define GENERAL_LIST_H - +#include #include #include diff --git a/Sources/Makefile b/Sources/Makefile index 2aaf935..7378690 100644 --- a/Sources/Makefile +++ b/Sources/Makefile @@ -45,12 +45,9 @@ UTEST_EXE = all_tests ## Source files to include and exclude ## LIBAFIS_SRCS = General/*.c \ - Extraction/Filters/*.c \ - Extraction/Model/*.c \ - Extraction/MinutiaeDetection/*.c \ - Extraction/*.c \ - Matcher/*.c \ - Matcher/Minutia/*.c + Extraction/Filters/*.c Extraction/Model/*.c Extraction/MinutiaeDetection/*.c Extraction/*.c \ + Templates/*.c \ + Matcher/*.c Matcher/Minutia/*.c LIBAFIS_SRCS_EXCLUDE = @@ -58,10 +55,11 @@ UTILS_SRCS = IO/*.c UTILS_SRCS_EXCLUDE = UTEST_SRCS = General/*.c General/runners/*.c \ - Extraction/Filters/*.c Extraction/Filters/runners/*.c \ - Extraction/Model/*.c Extraction/Model/runners/*.c \ - DataStructures/*.c Matcher/*.c Matcher/runners/*.c - + Extraction/Filters/*.c Extraction/Filters/runners/*.c Extraction/Model/*.c Extraction/Model/runners/*.c \ + DataStructures/*.c \ + EndToEnd/*.c \ + Matcher/*.c Matcher/runners/*.c + UTEST_SRCS_EXCLUDE = UTEST_SRCS += $(UTEST_EXE).c diff --git a/Sources/Templates/Minutia.h b/Sources/Templates/Minutia.h new file mode 100644 index 0000000..82c56e4 --- /dev/null +++ b/Sources/Templates/Minutia.h @@ -0,0 +1,17 @@ +#ifndef TEMPLATES_MINUTIA_H +#define TEMPLATES_MINUTIA_H + +#include "General/Point.h" + +#include + +typedef enum {ENDING = 0, BIFURCATION = 1, OTHER = 2} MinutiaType; + +typedef struct TemplateMinutia +{ + Point position; + uint8_t direction; + MinutiaType type; +} TemplateMinutia; + +#endif diff --git a/Sources/Templates/Template.c b/Sources/Templates/Template.c new file mode 100644 index 0000000..927fb79 --- /dev/null +++ b/Sources/Templates/Template.c @@ -0,0 +1,35 @@ +#include "Templates/Template.h" +#include "General/List.h" + +#include +#include + +void Template_AddMinuitia(Template *template, TemplateMinutia *minutia) +{ + List_AddData(&(template->minutiae), minutia); +} + +List *Template_GetMinutiae(Template *template) +{ + return &template->minutiae; +} + +Template Template_Constuct() +{ + Template template; + template.originalDpi = 0; + template.originalWidth = 0; + template.originalHeight = 0; + template.minutiae = List_Construct(); + return template; +} + +void Template_Free(Template *template) +{ + while (List_GetCount(&(template->minutiae)) > 0) + { + void *dataFound; + List_Remove(&(template->minutiae), (template->minutiae.tail), &dataFound); + free(dataFound); + } +} diff --git a/Sources/Templates/Template.h b/Sources/Templates/Template.h new file mode 100644 index 0000000..8477ede --- /dev/null +++ b/Sources/Templates/Template.h @@ -0,0 +1,20 @@ +#ifndef TEMPLATES_TEMPLATE_H +#define TEMPLATES_TEMPLATE_H + +#include "Templates/Minutia.h" +#include "General/List.h" +#include + +typedef struct Template +{ + int32_t originalDpi; + int32_t originalWidth; + int32_t originalHeight; + List minutiae; +} Template; + +Template Template_Constuct(void); +void Template_AddMinuitia(Template *, TemplateMinutia *); +void Template_Free(Template *); + +#endif diff --git a/Sources/Tests/EndToEnd/TestRunner_EndToEnd.c b/Sources/Tests/EndToEnd/TestRunner_EndToEnd.c new file mode 100644 index 0000000..a4387e5 --- /dev/null +++ b/Sources/Tests/EndToEnd/TestRunner_EndToEnd.c @@ -0,0 +1,7 @@ +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP_RUNNER(EndToEnd) +{ + RUN_TEST_CASE(EndToEnd, ImageToTemplate); +} diff --git a/Sources/Tests/EndToEnd/Test_EndToEnd.c b/Sources/Tests/EndToEnd/Test_EndToEnd.c new file mode 100644 index 0000000..c025144 --- /dev/null +++ b/Sources/Tests/EndToEnd/Test_EndToEnd.c @@ -0,0 +1,152 @@ +#include "Extraction/Extract.h" +#include "General/pgm.h" +#include "Templates/Template.h" +#include "unity.h" +#include "unity_fixture.h" +#include +#include + +TEST_GROUP(EndToEnd); + +static const char *inputFiles[] = +{ + "../TestImages/Person1/Bas1440999265-Hamster-0-0.png.pgm", + "../TestImages/Person1/Bas1440999265-Hamster-0-1.png.pgm", + "../TestImages/Person1/Bas1440999265-Hamster-0-2.png.pgm", + "../TestImages/Person1/Bas1440999265-Hamster-1-0.png.pgm", + "../TestImages/Person1/Bas1440999265-Hamster-1-1.png.pgm", + "../TestImages/Person1/Bas1440999265-Hamster-1-2.png.pgm" +}; + +TEST_SETUP(EndToEnd) +{ +} + +TEST_TEAR_DOWN(EndToEnd) +{ +} + +static void ReadTemplate(const char *expectedFileName, Template *expectedTemplate) +{ + FILE *f = fopen(expectedFileName, "rb"); + + int ret = fread(&expectedTemplate->originalDpi, sizeof(int32_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed originalDPI"); + + ret = fread(&expectedTemplate->originalHeight, sizeof(int32_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed originalHeight"); + + ret = fread(&expectedTemplate->originalWidth, sizeof(int32_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed originalWidth"); + + int32_t count; + ret = fread(&count, sizeof(int32_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed on minutiae count"); + + for(int i = 0; i < count; i++) + { + TemplateMinutia *minutia = calloc(1, sizeof(TemplateMinutia)); + + ret = fread(&(minutia->direction), sizeof(int8_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed on minutia->direction"); + + ret = fread(&(minutia->position.x), sizeof(int32_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed minutia->position.x"); + + ret = fread(&(minutia->position.y), sizeof(int32_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed minutia->position.y"); + + ret = fread(&(minutia->type), sizeof(int32_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed on minutia->type"); + + Template_AddMinuitia(expectedTemplate, minutia); + } + + /* Check end of file */ + uint8_t tmp; + ret = fread(&tmp, sizeof(uint8_t), 1, f); + TEST_ASSERT_TRUE_MESSAGE(ret == 0 && feof(f), "ReadTemplate: Bad end of file"); + + /* Close file */ + ret = fclose(f); + assert(ret != EOF); +} + + +static void UnityFreeTemplate(Template *template) +{ + while (List_GetCount(&template->minutiae) > 0) + { + void *dataFound; + List_Remove(&template->minutiae, template->minutiae.tail, &dataFound); + free(dataFound); + } +} + +static void ImageToTemplate(const char *inputFileName, const char *expectedFileName) +{ + UInt8Array2D image = pgm_read(inputFileName); + + TEST_ASSERT_TRUE_MESSAGE(image.sizeX > 1, "Image Size X < 1"); + TEST_ASSERT_TRUE_MESSAGE(image.sizeY > 1, "Image Size Y < 1"); + + struct perfdata perfdata; + + Template template = Template_Constuct(); + Template expectedTemplate = Template_Constuct(); + + printf("%s %s\r\n", inputFileName, expectedFileName); + + Extract(&image, &template, &perfdata, NULL, NULL); + + ReadTemplate(expectedFileName, &expectedTemplate); + + printf("originalDpi %d %d\n", expectedTemplate.originalDpi, template.originalDpi); + printf("originalWidth %d %d\n", expectedTemplate.originalWidth, template.originalWidth); + printf("originalHeight %d %d\n", expectedTemplate.originalHeight, template.originalHeight); + printf("#minutiae %d %d\n", expectedTemplate.minutiae.count, template.minutiae.count); + List matching = List_Construct(); + List missingFromExpected = List_Construct(); + List missingFromTemplate= List_Construct(); + + for (ListElement *i = expectedTemplate.minutiae.head; i != NULL; i = i->next) + { + TemplateMinutia *expected = i->data; + bool found = false; + for (ListElement *j = template.minutiae.head; j != NULL; j = j->next) + { + TemplateMinutia *templateMin = i->data; + if ((templateMin->type == expected->type) && (templateMin->direction == expected->direction) && (templateMin->position.x == expected->position.x) && (templateMin->position.y == expected->position.y)) + { + List_AddData(&matching, expected); + found = true; + } + } + if (!found) + { + List_AddData(&missingFromTemplate, expected); + } + } + if (expectedTemplate.minutiae.count > 0) + { + printf("Matching = %d%%\n", matching.count * 100 / expectedTemplate.minutiae.count); + printf("Missing from template = %d%%\n", missingFromTemplate.count * 100 / expectedTemplate.minutiae.count); + printf("Missing from expected = %d%%\n", missingFromExpected.count * 100 / expectedTemplate.minutiae.count); + } + + + UnityFreeTemplate(&template); + UnityFreeTemplate(&expectedTemplate); +} + +TEST(EndToEnd, ImageToTemplate) +{ + int length = sizeof(inputFiles) / sizeof(inputFiles[0]); + for(int i = 0; i < length; i++) + { + char templateFile[256]; + strcpy(templateFile, inputFiles[i]); + strcat(templateFile, ".template"); + ImageToTemplate(inputFiles[i], templateFile); + } +} diff --git a/Sources/Tests/Extraction/Filters/Test_VotingFilter.c b/Sources/Tests/Extraction/Filters/Test_VotingFilter.c index f8e31ab..cdf462a 100644 --- a/Sources/Tests/Extraction/Filters/Test_VotingFilter.c +++ b/Sources/Tests/Extraction/Filters/Test_VotingFilter.c @@ -45,7 +45,7 @@ TEST(VotingFilter, VotingFilter_regression_tests_against_sourceAfis) sprintf(inputFile, "%s.input.dat", regressionFiles[i]); - printf("File = %s\r\n", inputFile); +// printf("File = %s\r\n", inputFile); sprintf(outputFile, "%s.result.dat", regressionFiles[i]); sprintf(paramRadius, "%s.Radius.dat", regressionFiles[i]); sprintf(paramMajority, "%s.Majority.dat", regressionFiles[i]); diff --git a/Sources/Tests/General/Test_List.c b/Sources/Tests/General/Test_List.c new file mode 100644 index 0000000..f5d949a --- /dev/null +++ b/Sources/Tests/General/Test_List.c @@ -0,0 +1,82 @@ +#include "unity.h" +#include "unity_fixture.h" +#include "General/List.h" +#include "Templates/Template.h" + +TEST_GROUP(List); + +TEST_SETUP(List) +{ +} + +TEST_TEAR_DOWN(List) +{ +} + +#define MAX_NUMBER_ELEMENTS 10000 +TEST(List, TestListWithNoData) +{ + List list = List_Construct(); + for (int i = 0; i < MAX_NUMBER_ELEMENTS; i++) + { + List_AddData(&list, (void *)(long)i); + } + TEST_ASSERT_EQUAL_INT_MESSAGE(MAX_NUMBER_ELEMENTS, List_GetCount(&list), "List is not correct size"); + while(list.head != NULL) + { + List_Remove(&list, list.head, NULL); + } + TEST_ASSERT_EQUAL_INT_MESSAGE(0, List_GetCount(&list), "List is not empty but was expected so..."); +} + +TEST(List, TestListRemoval) +{ + List list = List_Construct(); + for (int i = 0; i < MAX_NUMBER_ELEMENTS; i++) + { + List_AddData(&list, (void *)(long)i); + } + long idToRemove = (MAX_NUMBER_ELEMENTS/2); + List_RemoveData(&list, (void *) (long) idToRemove ); + TEST_ASSERT_EQUAL_INT_MESSAGE(MAX_NUMBER_ELEMENTS-1, List_GetCount(&list), "List is not right length"); + + for (ListElement *p = list.head; p != NULL; p = p->next) + { + TEST_ASSERT_NOT_EQUAL_MESSAGE(idToRemove, (long)p->data, "Found data we have removed!"); + } + + while(list.head != NULL) + { + List_Remove(&list, list.head, NULL); + } + TEST_ASSERT_EQUAL_INT_MESSAGE(0, List_GetCount(&list), "List is not empty but was expected so..."); +} + +typedef struct _fred +{ + List Points; +} FRED; + +TEST(List, TestListDyanmicMemoryAlloc) +{ + FRED data; + { + List list1 = List_Construct(); + data.Points = list1; + } + + for (int i = 0; i< MAX_NUMBER_ELEMENTS; i++) + { + void *data1 = calloc(1, sizeof(TemplateMinutia)); + List_AddData(&data.Points, data1); + } + + while (List_GetCount(&data.Points) > 0) + { + void *dataFound; + List_Remove(&data.Points, data.Points.head, &dataFound); + free(dataFound); + } + + +} \ No newline at end of file diff --git a/Sources/Tests/General/runners/TestRunner_List.c b/Sources/Tests/General/runners/TestRunner_List.c new file mode 100644 index 0000000..633c5b8 --- /dev/null +++ b/Sources/Tests/General/runners/TestRunner_List.c @@ -0,0 +1,9 @@ +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP_RUNNER(List) +{ + RUN_TEST_CASE(List, TestListWithNoData); + RUN_TEST_CASE(List, TestListRemoval); + RUN_TEST_CASE(List, TestListDyanmicMemoryAlloc); +} diff --git a/Sources/Tests/all_tests.c b/Sources/Tests/all_tests.c index e99cf2e..fd7207c 100644 --- a/Sources/Tests/all_tests.c +++ b/Sources/Tests/all_tests.c @@ -15,12 +15,15 @@ static void RunAllTests(void) printf("\nPoint tests\n"); RUN_TEST_GROUP(Point); - + printf("\nArray tests\n"); RUN_TEST_GROUP(Array); - + printf("\nBinaryMap tests\n"); RUN_TEST_GROUP(BinaryMap); + + printf("\nList tests\n"); + RUN_TEST_GROUP(List); printf("\nCalc tests\n"); RUN_TEST_GROUP(Calc); @@ -43,6 +46,9 @@ static void RunAllTests(void) printf("\nEqualizer tests\n"); RUN_TEST_GROUP(Equalizer); + printf("\nEnd to End Image to Template tests\n"); + RUN_TEST_GROUP(EndToEnd); + printf("\nThinner tests\n"); RUN_TEST_GROUP(Thinner); diff --git a/Sources/Tests/extract.c b/Sources/Tests/extract.c index e32e4cb..5a13fbd 100644 --- a/Sources/Tests/extract.c +++ b/Sources/Tests/extract.c @@ -4,6 +4,7 @@ #include "General/Array.h" #include "General/BinaryMap.h" #include "General/pgm.h" +#include "Templates/Template.h" double diff(struct timeval x, struct timeval y) { @@ -33,20 +34,22 @@ int main(int argc, char* argv[]) if (image.sizeX == 1 && image.sizeY == 1) continue; + Template template; struct perfdata perfdata; UInt8Array2D binarizedImage = UInt8Array2D_Construct(image.sizeX, image.sizeY); UInt8Array2D thinnedImage = UInt8Array2D_Construct(image.sizeX, image.sizeY); - Extract(&image, &perfdata, &binarizedImage, &thinnedImage); + Extract(&image, &template, &perfdata, &binarizedImage, &thinnedImage); - printf("Histogram generation: %f\n", diff(perfdata.start_segmentation, perfdata.start_histogram)); - printf(" Segmentation: %f\n", diff(perfdata.start_equalization, perfdata.start_segmentation)); - printf(" Equalization: %f\n", diff(perfdata.start_orientation, perfdata.start_equalization)); - printf(" Orientation: %f\n", diff(perfdata.start_binarisation, perfdata.start_orientation)); - printf(" Binarisation: %f\n", diff(perfdata.start_thinning, perfdata.start_binarisation)); - printf(" Ridge thinning: %f\n", diff(perfdata.start_detection, perfdata.start_thinning)); - printf(" Minutiae detection: %f\n", diff(perfdata.start_filtering, perfdata.start_detection)); - printf(" Minutiae filtering: %f\n", diff(perfdata.end, perfdata.start_filtering)); - printf(" TOTAL: %f\n", diff(perfdata.end, perfdata.start)); + printf(" Histogram generation: %f\n", diff(perfdata.start_segmentation, perfdata.start_histogram)); + printf(" Segmentation: %f\n", diff(perfdata.start_equalization, perfdata.start_segmentation)); + printf(" Equalization: %f\n", diff(perfdata.start_orientation, perfdata.start_equalization)); + printf(" Orientation: %f\n", diff(perfdata.start_binarisation, perfdata.start_orientation)); + printf(" Binarisation: %f\n", diff(perfdata.start_thinning, perfdata.start_binarisation)); + printf(" Ridge thinning: %f\n", diff(perfdata.start_detection, perfdata.start_thinning)); + printf(" Minutiae detection: %f\n", diff(perfdata.start_filtering, perfdata.start_detection)); + printf(" Minutiae filtering: %f\n", diff(perfdata.end, perfdata.start_filtering)); + printf("Template construction: %f\n", diff(perfdata.end, perfdata.start_template)); + printf(" TOTAL: %f\n", diff(perfdata.end, perfdata.start)); int filenameLen = strlen(filename); diff --git a/TestImages/Person1/Bas1440999265-Hamster-0-0.png.pgm.template b/TestImages/Person1/Bas1440999265-Hamster-0-0.png.pgm.template new file mode 100755 index 0000000..c0aa682 Binary files /dev/null and b/TestImages/Person1/Bas1440999265-Hamster-0-0.png.pgm.template differ diff --git a/TestImages/Person1/Bas1440999265-Hamster-0-1.png.pgm.template b/TestImages/Person1/Bas1440999265-Hamster-0-1.png.pgm.template new file mode 100755 index 0000000..ae22f4c Binary files /dev/null and b/TestImages/Person1/Bas1440999265-Hamster-0-1.png.pgm.template differ diff --git a/TestImages/Person1/Bas1440999265-Hamster-0-2.png.pgm.template b/TestImages/Person1/Bas1440999265-Hamster-0-2.png.pgm.template new file mode 100755 index 0000000..a4e51b1 Binary files /dev/null and b/TestImages/Person1/Bas1440999265-Hamster-0-2.png.pgm.template differ diff --git a/TestImages/Person1/Bas1440999265-Hamster-1-0.png.pgm.template b/TestImages/Person1/Bas1440999265-Hamster-1-0.png.pgm.template new file mode 100755 index 0000000..fa19cd4 Binary files /dev/null and b/TestImages/Person1/Bas1440999265-Hamster-1-0.png.pgm.template differ diff --git a/TestImages/Person1/Bas1440999265-Hamster-1-1.png.pgm.template b/TestImages/Person1/Bas1440999265-Hamster-1-1.png.pgm.template new file mode 100755 index 0000000..153e7e3 Binary files /dev/null and b/TestImages/Person1/Bas1440999265-Hamster-1-1.png.pgm.template differ diff --git a/TestImages/Person1/Bas1440999265-Hamster-1-2.png.pgm.template b/TestImages/Person1/Bas1440999265-Hamster-1-2.png.pgm.template new file mode 100755 index 0000000..87e4b34 Binary files /dev/null and b/TestImages/Person1/Bas1440999265-Hamster-1-2.png.pgm.template differ