Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a6763c4
Correct spellink...
Nov 5, 2015
a99bca6
Start on ISO/IEC 19794-2:2005 template support.
Nov 5, 2015
c16500c
Initial stab at an ISO/IEC 19794-2:2005 template writer
Nov 6, 2015
dffbe31
Add minutia to the ISO/IEC 19794-2:2005 template output.
Nov 6, 2015
671019a
Stop the coredump when trying to free non dynamically allocated moemo…
Nov 6, 2015
98e0483
Switch back to removing from head, rather than tail.
Nov 6, 2015
2415b42
Add an ISO/IEC 19794-2:2005 template input routine...
Nov 6, 2015
509ef3e
Merge branch 'master' into isotemplate-io
Nov 6, 2015
7cf3c80
Merge branch 'image-to-template-test' into isotemplate-io
Nov 6, 2015
a7617c9
Calculate and add in the template length when exporting
Nov 6, 2015
7f8ba14
Merge branch 'master' into isotemplate-io
Nov 6, 2015
20e8b80
Merge branch 'master' into isotemplate-io
Nov 6, 2015
a432bbb
Merge branch 'image-to-template-test' into isotemplate-io
Nov 6, 2015
015c6af
Get rid of an auto-generated comment and some hanging chars on anothe…
Nov 6, 2015
fda3fe2
Include <stdlib.h> not <malloc.h>
Nov 6, 2015
e783e94
Merge branch 'image-to-template-test' into isotemplate-io
Nov 6, 2015
c7e9d79
Merge branch 'master' into isotemplate-io
Nov 7, 2015
823304b
Merge branch 'fix-mem-leaks' into isotemplate-io
Nov 8, 2015
dbf92d6
remove the duplicate .c from the end fo the file name
Nov 8, 2015
0511010
Update the VS Solution
Nov 11, 2015
5d0c22b
Revert "Update the VS Solution"
Nov 11, 2015
e6a7c26
Merge branch 'master' into isotemplate-io
Nov 11, 2015
220272b
Turns out the TEST_SETUP and TEST_TEAR_DOWN weren't being called when…
Nov 11, 2015
edfddac
W00t! Fix the memory leakage by freeing the right stuff with the righ…
Nov 11, 2015
dd334b2
Merge branch 'master' into isotemplate-io
Nov 11, 2015
7bc52c0
Merge branch 'image-to-template-test' into isotemplate-io
Nov 11, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Sources/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ UTEST_SRCS = General/*.c General/runners/*.c \
Extraction/Filters/*.c Extraction/Filters/runners/*.c Extraction/Model/*.c Extraction/Model/runners/*.c \
DataStructures/*.c \
EndToEnd/*.c \
Templates/*.c \
Matcher/*.c Matcher/runners/*.c

UTEST_SRCS_EXCLUDE =
Expand Down
11 changes: 3 additions & 8 deletions Sources/Templates/Template.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <stdlib.h>
#include <assert.h>

void Template_AddMinuitia(Template *template, TemplateMinutia *minutia)
void Template_AddMinutia(Template *template, TemplateMinutia *minutia)
Copy link
Collaborator

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 const consistently? I'd have thought both should be const in this situation?

Copy link
Collaborator Author

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...

{
List_AddData(&(template->minutiae), minutia);
}
Expand All @@ -14,7 +14,7 @@ List *Template_GetMinutiae(Template *template)
return &template->minutiae;
}

Template Template_Constuct()
Template Template_Construct()
{
Template template;
template.originalDpi = 0;
Expand All @@ -26,10 +26,5 @@ Template Template_Constuct()

void Template_Free(Template *template)
{
while (List_GetCount(&(template->minutiae)) > 0)
{
void *dataFound;
List_Remove(&(template->minutiae), (template->minutiae.tail), &dataFound);
free(dataFound);
}
List_Destroy(&(template->minutiae), &(free));
}
4 changes: 2 additions & 2 deletions Sources/Templates/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ typedef struct Template
List minutiae;
} Template;

Template Template_Constuct(void);
void Template_AddMinuitia(Template *, TemplateMinutia *);
Template Template_Construct(void);
void Template_AddMinutia(Template *, TemplateMinutia *);
void Template_Free(Template *);

#endif
298 changes: 298 additions & 0 deletions Sources/Templates/TemplateIO.c
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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const

What about error handling? Should this return non-zero on failure with an appropriate error code? (rather than assert?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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...

Copy link
Collaborator

Choose a reason for hiding this comment

The 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)
Copy link
Collaborator

Choose a reason for hiding this comment

The 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)));
}
9 changes: 9 additions & 0 deletions Sources/Templates/TemplateIO.h
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
8 changes: 3 additions & 5 deletions Sources/Tests/EndToEnd/Test_EndToEnd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -72,7 +72,6 @@ static void ReadTemplate(const char *expectedFileName, Template *expectedTemplat
assert(ret != EOF);
}


static void UnityFreeTemplate(Template *template)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got really confused about the UnityFree stuff - can someone explain why it is necessary?

I see that malloc and free are redefined, but what's it doing differently that means we have to duplicate code in our tests?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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.

Copy link
Collaborator

Choose a reason for hiding this comment

The 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.
As @fatboab says it seems like Unity does it's own tracking, so you cann't free under Unity if it wasn't allocated under Unity. I am sure that there is ways of disabling this feature or turning it off or enhancing Unity, but I did not look at that...

Copy link
Collaborator

Choose a reason for hiding this comment

The 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 (const) or unrelated to this (use of unity), so I'm happy for this to be merged!

{
while (List_GetCount(&template->minutiae) > 0)
Expand All @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down
Loading