-
Notifications
You must be signed in to change notification settings - Fork 27
ISO/IEC 19794-2:2005 Template IO #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: image-to-template-test
Are you sure you want to change the base?
Changes from all commits
a6763c4
a99bca6
c16500c
dffbe31
671019a
98e0483
2415b42
509ef3e
7cf3c80
a7617c9
7f8ba14
20e8b80
a432bbb
015c6af
fda3fe2
e783e94
c7e9d79
823304b
dbf92d6
0511010
5d0c22b
e6a7c26
220272b
edfddac
dd334b2
7bc52c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,298 @@ | ||
| #include "General/Calc.h" | ||
| #include "Templates/TemplateIO.h" | ||
|
|
||
| #include <assert.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| // Format (all numbers are big-endian): | ||
| // 4B magic "FMR\0" | ||
| // 4B version (ignored, set to " 20\0" | ||
| // 4B total length (including header) | ||
| // 2B rubbish (zeroed) | ||
| // 2B image size in pixels X | ||
| // 2B image size in pixels Y | ||
| // 2B rubbish (pixels per cm X, set to 196 = 500dpi) | ||
| // 2B rubbish (pixels per cm Y, set to 196 = 500dpi) | ||
| // 1B rubbish (number of fingerprints, set to 1) | ||
| // 1B rubbish (zeroed) | ||
| // 1B rubbish (finger position, zeroed) | ||
| // 1B rubbish (zeroed) | ||
| // 1B rubbish (fingerprint quality, set to 100) | ||
| // 1B minutia count | ||
| // N*6B minutiae | ||
| // 2B minutia position X in pixels | ||
| // 2b (upper) minutia type (01 ending, 10 bifurcation, 00 other) | ||
| // 2B minutia position Y in pixels (upper 2b ignored, zeroed) | ||
| // 1B direction, compatible with SourceAFIS angles | ||
| // 1B quality (ignored, zeroed) | ||
| // 2B rubbish (extra data length, zeroed) | ||
| // N*1B rubbish (extra data) | ||
| void TemplateIO_ISO19794_2_2005_Export(Template *template, const char *outputFileName) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What about error handling? Should this return non-zero on failure with an appropriate error code? (rather than
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the boiler plate code that in the project before we stared used assert, so we just continued. I suppose this is another of those library wide questions that we need to agree on...
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am happy with asserts in the test code, but not in the library, to me the library code should be bullet-proof no way it can go wrong. It can fail to load a file or save a file, but if it fails all is good nothing bad happens, bar the file not being saved. (OK Yes I know tests aren't 2nd class citizens.) |
||
| { | ||
| // Open a binary file to output the template to... | ||
| FILE *output = fopen(outputFileName, "wb"); | ||
|
|
||
| // 4B magic "FMR\0" | ||
| char magic[] = {'F', 'M', 'R', '\0'}; | ||
| int count = fwrite(magic, sizeof(magic), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 4B version (ignored, set to " 20\0" | ||
| char version[] = {' ', '2', '0', '\0'}; | ||
| count = fwrite(version, sizeof(version), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 4B total length (28 bytes for the header, 6 bytes for each minutia and 2 bytes footer padding) | ||
| int32_t totalLength = 30 + (List_GetCount(&template->minutiae) * 6); | ||
| count = fwrite(&totalLength, sizeof(totalLength), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 2B rubbish (zeroed) | ||
| int16_t twoByteRubbish = 0; | ||
| count = fwrite(&twoByteRubbish, sizeof(twoByteRubbish), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 2B image size in pixels X | ||
| int16_t imageSizeX = Calc_DivRoundUp(template->originalWidth * 500, template->originalDpi); | ||
| count = fwrite(&imageSizeX, sizeof(imageSizeX), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 2B image size in pixels Y | ||
| int16_t imageSizeY = Calc_DivRoundUp(template->originalHeight * 500, template->originalDpi); | ||
| count = fwrite(&imageSizeY, sizeof(imageSizeY), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 2B rubbish (pixels per cm X, set to 196 = 500dpi) | ||
| int16_t pixelsPerCm = 196; | ||
| count = fwrite(&pixelsPerCm, sizeof(pixelsPerCm), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 2B rubbish (pixels per cm Y, set to 196 = 500dpi) | ||
| count = fwrite(&pixelsPerCm, sizeof(pixelsPerCm), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (number of fingerprints, set to 1) | ||
| int8_t oneByteRubbish = 1; | ||
| count = fwrite(&oneByteRubbish, sizeof(oneByteRubbish), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (zeroed) | ||
| oneByteRubbish = 0; | ||
| count = fwrite(&oneByteRubbish, sizeof(oneByteRubbish), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (finger position, zeroed) | ||
| count = fwrite(&oneByteRubbish, sizeof(oneByteRubbish), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (zeroed) | ||
| count = fwrite(&oneByteRubbish, sizeof(oneByteRubbish), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (fingerprint quality, set to 100) | ||
| int8_t fingerprintQuality = 100; | ||
| count = fwrite(&fingerprintQuality, sizeof(fingerprintQuality), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B minutia count | ||
| int8_t minutiaCount = List_GetCount(&template->minutiae); | ||
| count = fwrite(&minutiaCount, sizeof(int8_t), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // N*6B minutiae | ||
| for (ListElement *element = template->minutiae.head; element != NULL; element = element->next) | ||
| { | ||
| // Get the minutia from the list element... | ||
| TemplateMinutia *minutia = element->data; | ||
|
|
||
| // 2B minutia position X in pixels | ||
| // 2b (upper) minutia type (01 ending, 10 bifurcation, 00 other (considered ending)) | ||
| int16_t x = minutia->position.x; | ||
| assert(x <= 0x3fff); | ||
|
|
||
| uint16_t type; | ||
| switch (minutia->type) | ||
| { | ||
| case ENDING: | ||
| type = 0x4000; | ||
| break; | ||
| case BIFURCATION: | ||
| type = 0x8000; | ||
| break; | ||
| case OTHER: | ||
| type = 0; | ||
| break; | ||
| default: | ||
| assert(false); | ||
| } | ||
| uint16_t combined = (x | type); | ||
| count = fwrite(&combined, sizeof(uint16_t), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 2B minutia position Y in pixels (upper 2b ignored, zeroed) | ||
| int16_t y = imageSizeY - minutia->position.y - 1; | ||
| assert(y <= 0x3fff); | ||
| count = fwrite(&y, sizeof(int16_t), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B direction, compatible with SourceAFIS angles | ||
| count = fwrite(&minutia->direction, sizeof(uint8_t), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // 1B quality (ignored, zeroed) | ||
| count = fwrite(&oneByteRubbish, sizeof(oneByteRubbish), 1, output); | ||
| assert(count == 1); | ||
| } | ||
|
|
||
| // 2B rubbish (extra data length, zeroed) | ||
| // N*1B rubbish (extra data) | ||
| count = fwrite(&twoByteRubbish, sizeof(twoByteRubbish), 1, output); | ||
| assert(count == 1); | ||
|
|
||
| // Flush and close the binary file... | ||
| fflush(output); | ||
| fclose(output); | ||
| } | ||
|
|
||
| void TemplateIO_ISO19794_2_2005_Import(const char *inputFileName, Template *template) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto on the error handling. |
||
| { | ||
| // Open a binary file to output the template to... | ||
| FILE *input = fopen(inputFileName, "rb"); | ||
|
|
||
| // ::TODO:: Decide if this is acceptable or not, it's what SourceAFIS does... | ||
| template->originalDpi = 500; | ||
|
|
||
| // 4B magic "FMR\0" | ||
| char header[4]; | ||
| int count = fread(header, sizeof(uint8_t) * 4, 1, input); | ||
| assert(count == 1); | ||
| assert(strcmp("FMR", header) == 0); | ||
|
|
||
| char version[4]; | ||
| count = fread(version, sizeof(version), 1, input); | ||
| assert(count == 1); | ||
| assert(strcmp(" 20", version) == 0); | ||
|
|
||
| // 4B total length | ||
| int32_t totalLength; | ||
| count = fread(&totalLength, sizeof(int32_t), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 2B rubbish (zeroed) | ||
| int16_t twoByteRubbish; | ||
| count = fread(&twoByteRubbish, sizeof(twoByteRubbish), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 2B image size in pixels X | ||
| int16_t imageSizeX; | ||
| count = fread(&imageSizeX, sizeof(imageSizeX), 1, input); | ||
| assert(count == 1); | ||
| template->originalWidth = (imageSizeX * template-> originalDpi) / 500; | ||
|
|
||
| // 2B image size in pixels Y | ||
| int16_t imageSizeY; | ||
| count = fread(&imageSizeY, sizeof(imageSizeY), 1, input); | ||
| assert(count == 1); | ||
| template->originalHeight = (imageSizeY * template->originalDpi) / 500; | ||
|
|
||
| // 2B rubbish (pixels per cm X, set to 196 = 500dpi) | ||
| int16_t pixelsPerCm; | ||
| count = fread(&pixelsPerCm, sizeof(pixelsPerCm), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 2B rubbish (pixels per cm Y, set to 196 = 500dpi) | ||
| count = fread(&pixelsPerCm, sizeof(pixelsPerCm), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (number of fingerprints, set to 1) | ||
| int8_t oneByteRubbish; | ||
| count = fread(&oneByteRubbish, sizeof(oneByteRubbish), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (zeroed) | ||
| count = fread(&oneByteRubbish, sizeof(oneByteRubbish), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (finger position, zeroed) | ||
| count = fread(&oneByteRubbish, sizeof(oneByteRubbish), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (zeroed) | ||
| count = fread(&oneByteRubbish, sizeof(oneByteRubbish), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 1B rubbish (fingerprint quality, set to 100) | ||
| int8_t fingerprintQuality; | ||
| count = fread(&fingerprintQuality, sizeof(fingerprintQuality), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 1B minutia count | ||
| int8_t minutiaCount; | ||
| count = fread(&minutiaCount, sizeof(int8_t), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // N*6B minutiae | ||
| for (int ii = 0; ii < minutiaCount; ++ii) | ||
| { | ||
| TemplateMinutia *templateMinutia = malloc(sizeof(TemplateMinutia)); | ||
|
|
||
| // 2B minutia position X in pixels | ||
| // 2b (upper) minutia type (01 ending, 10 bifurcation, 00 other (considered ending)) | ||
| uint16_t combined, type; | ||
| int16_t x; | ||
| count = fread(&combined, sizeof(uint16_t), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| x = combined & 0x3FFF; | ||
| switch(combined & 0xc000) | ||
| { | ||
| case 0x4000: | ||
| type = ENDING; | ||
| break; | ||
| case 0x8000: | ||
| type = BIFURCATION; | ||
| break; | ||
| case 0: | ||
| type = OTHER; | ||
| break; | ||
| default: | ||
| assert("Incorrect minutia type"); | ||
| } | ||
|
|
||
| // 2B minutia position Y in pixels (upper 2b ignored, zeroed) | ||
| int16_t y; | ||
| count = fread(&y, sizeof(int16_t), 1, input); | ||
| assert(count == 1); | ||
| y = template->originalHeight - 1 - (y & 0x3fff); | ||
| assert(y <= 0x3fff); | ||
|
|
||
| // 1B direction, compatible with SourceAFIS angles | ||
| uint8_t direction; | ||
| count = fread(&direction, sizeof(uint8_t), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // 1B quality (ignored, zeroed) | ||
| count = fread(&oneByteRubbish, sizeof(oneByteRubbish), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // Add the minutia to the template list... | ||
| templateMinutia->position = (Point) {.x = x, .y = y}; | ||
| templateMinutia->direction = direction; | ||
| templateMinutia->type = type; | ||
| Template_AddMinutia(template, templateMinutia); | ||
| } | ||
|
|
||
| // 2B rubbish (extra data length, zeroed) | ||
| // N*1B rubbish (extra data) | ||
| count = fread(&twoByteRubbish, sizeof(twoByteRubbish), 1, input); | ||
| assert(count == 1); | ||
|
|
||
| // Close the binary file... | ||
| fclose(input); | ||
|
|
||
| // Confirm total length... | ||
| assert(totalLength == (30 + (minutiaCount * 6))); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| #ifndef LIBAFIS_TEMPLATEIO_H | ||
| #define LIBAFIS_TEMPLATEIO_H | ||
|
|
||
| #include "Templates/Template.h" | ||
|
|
||
| void TemplateIO_ISO19794_2_2005_Export(Template *, const char *); | ||
| void TemplateIO_ISO19794_2_2005_Import(const char *, Template *); | ||
|
|
||
| #endif //LIBAFIS_TEMPLATEIO_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,7 +59,7 @@ static void ReadTemplate(const char *expectedFileName, Template *expectedTemplat | |
| ret = fread(&(minutia->type), sizeof(int32_t), 1, f); | ||
| TEST_ASSERT_TRUE_MESSAGE(ret == 1, "ReadTemplate: failed on minutia->type"); | ||
|
|
||
| Template_AddMinuitia(expectedTemplate, minutia); | ||
| Template_AddMinutia(expectedTemplate, minutia); | ||
| } | ||
|
|
||
| /* Check end of file */ | ||
|
|
@@ -72,7 +72,6 @@ static void ReadTemplate(const char *expectedFileName, Template *expectedTemplat | |
| assert(ret != EOF); | ||
| } | ||
|
|
||
|
|
||
| static void UnityFreeTemplate(Template *template) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I got really confused about the I see that
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @david-connell can explain it better than I can, but the Unity stuff adds extra stuff into the malloc so it can track it, if we free with the normal free, rather than the Unity free, then this extra stuff is leaked and the test fails.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @fffej , the rule is pretty simple, if you allocate under unity then free under unity, if you malloc normally then free normally.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @david-connell Thanks! I guess I'd love to disable that malloc stuff, since valgrind does that job for us. Most of the things I've mentioned are library related ( |
||
| { | ||
| while (List_GetCount(&template->minutiae) > 0) | ||
|
|
@@ -92,8 +91,8 @@ static void ImageToTemplate(const char *inputFileName, const char *expectedFileN | |
|
|
||
| struct perfdata perfdata; | ||
|
|
||
| Template template = Template_Constuct(); | ||
| Template expectedTemplate = Template_Constuct(); | ||
| Template template = Template_Construct(); | ||
| Template expectedTemplate = Template_Construct(); | ||
|
|
||
| printf("%s %s\r\n", inputFileName, expectedFileName); | ||
|
|
||
|
|
@@ -134,7 +133,6 @@ static void ImageToTemplate(const char *inputFileName, const char *expectedFileN | |
| printf("Missing from expected = %d%%\n", missingFromExpected.count * 100 / expectedTemplate.minutiae.count); | ||
| } | ||
|
|
||
|
|
||
| UnityFreeTemplate(&template); | ||
| UnityFreeTemplate(&expectedTemplate); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we going to use
constconsistently? I'd have thought both should beconstin this situation?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea, we need to decide on a few things like that and then apply them to all the code in another branch I think...