summaryrefslogtreecommitdiff
path: root/libfprint
diff options
context:
space:
mode:
authorVasily Khoruzhick <anarsoul@gmail.com>2013-02-18 12:27:33 +0300
committerVasily Khoruzhick <anarsoul@gmail.com>2013-08-19 11:13:49 +0300
commite215b0509448e05bf7a352317bc3282a9d5fd437 (patch)
treefec97cb1125421b943f4a62b734cd401ffd25aba /libfprint
parentfe3fdd1f5061d3b6fa172758c07705f8bfcb6d07 (diff)
imgdev: perform 5 scans for enrollment
This feature dramatically improves matching rate on devices with small sensors.
Diffstat (limited to 'libfprint')
-rw-r--r--libfprint/data.c161
-rw-r--r--libfprint/drivers/upeke2.c12
-rw-r--r--libfprint/drivers/upekts.c12
-rw-r--r--libfprint/fp_internal.h20
-rw-r--r--libfprint/img.c78
-rw-r--r--libfprint/imgdev.c32
6 files changed, 247 insertions, 68 deletions
diff --git a/libfprint/data.c b/libfprint/data.c
index bfbf8fb..3c138c3 100644
--- a/libfprint/data.c
+++ b/libfprint/data.c
@@ -95,21 +95,33 @@ static const char *finger_num_to_str(enum fp_finger finger)
#endif
static struct fp_print_data *print_data_new(uint16_t driver_id,
- uint32_t devtype, enum fp_print_data_type type, size_t length)
+ uint32_t devtype, enum fp_print_data_type type)
{
- struct fp_print_data *data = g_malloc0(sizeof(*data) + length);
- fp_dbg("length=%zd driver=%02x devtype=%04x", length, driver_id, devtype);
+ struct fp_print_data *data = g_malloc0(sizeof(*data));
+ fp_dbg("driver=%02x devtype=%04x", driver_id, devtype);
data->driver_id = driver_id;
data->devtype = devtype;
data->type = type;
- data->length = length;
return data;
}
-struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length)
+void fpi_print_data_item_free(struct fp_print_data_item *item)
+{
+ g_free(item);
+}
+
+struct fp_print_data_item *fpi_print_data_item_new(size_t length)
+{
+ struct fp_print_data_item *item = g_malloc(sizeof(*item) + length);
+ item->length = length;
+
+ return item;
+}
+
+struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
{
return print_data_new(dev->drv->id, dev->devtype,
- fpi_driver_get_data_type(dev->drv), length);
+ fpi_driver_get_data_type(dev->drv));
}
/** \ingroup print_data
@@ -124,27 +136,115 @@ struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length)
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
unsigned char **ret)
{
- struct fpi_print_data_fp1 *buf;
- size_t buflen;
+ struct fpi_print_data_fp2 *out_data;
+ struct fpi_print_data_item_fp2 *out_item;
+ struct fp_print_data_item *item;
+ size_t buflen = 0;
+ GSList *list_item;
+ unsigned char *buf;
fp_dbg("");
- buflen = sizeof(*buf) + data->length;
- buf = malloc(buflen);
- if (!buf)
- return 0;
-
- *ret = (unsigned char *) buf;
- buf->prefix[0] = 'F';
- buf->prefix[1] = 'P';
- buf->prefix[2] = '1';
- buf->driver_id = GUINT16_TO_LE(data->driver_id);
- buf->devtype = GUINT32_TO_LE(data->devtype);
- buf->data_type = data->type;
- memcpy(buf->data, data->data, data->length);
+ list_item = data->prints;
+ while (list_item) {
+ item = list_item->data;
+ buflen += sizeof(*out_item);
+ buflen += item->length;
+ list_item = g_slist_next(list_item);
+ }
+
+ buflen += sizeof(*out_data);
+ out_data = g_malloc(buflen);
+
+ *ret = (unsigned char *) out_data;
+ buf = out_data->data;
+ out_data->prefix[0] = 'F';
+ out_data->prefix[1] = 'P';
+ out_data->prefix[2] = '2';
+ out_data->driver_id = GUINT16_TO_LE(data->driver_id);
+ out_data->devtype = GUINT32_TO_LE(data->devtype);
+ out_data->data_type = data->type;
+
+ list_item = data->prints;
+ while (list_item) {
+ item = list_item->data;
+ out_item = (struct fpi_print_data_item_fp2 *)buf;
+ out_item->length = GUINT32_TO_LE(item->length);
+ /* FIXME: fp_print_data_item->data content is not endianess agnostic */
+ memcpy(out_item->data, item->data, item->length);
+ buf += sizeof(*out_item);
+ buf += item->length;
+ list_item = g_slist_next(list_item);
+ }
+
return buflen;
}
+static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
+ size_t buflen)
+{
+ size_t print_data_len;
+ struct fp_print_data *data;
+ struct fp_print_data_item *item;
+ struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
+
+ print_data_len = buflen - sizeof(*raw);
+ data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
+ GUINT32_FROM_LE(raw->devtype), raw->data_type);
+ item = fpi_print_data_item_new(print_data_len);
+ /* FIXME: fp_print_data->data content is not endianess agnostic */
+ memcpy(item->data, raw->data, print_data_len);
+ data->prints = g_slist_prepend(data->prints, item);
+
+ return data;
+}
+
+static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
+ size_t buflen)
+{
+ size_t total_data_len, item_len;
+ struct fp_print_data *data;
+ struct fp_print_data_item *item;
+ struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
+ unsigned char *raw_buf;
+ struct fpi_print_data_item_fp2 *raw_item;
+
+ total_data_len = buflen - sizeof(*raw);
+ data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
+ GUINT32_FROM_LE(raw->devtype), raw->data_type);
+ raw_buf = raw->data;
+ while (total_data_len) {
+ if (total_data_len < sizeof(*raw_item))
+ break;
+ total_data_len -= sizeof(*raw_item);
+
+ raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
+ item_len = GUINT32_FROM_LE(raw_item->length);
+ fp_dbg("item len %d, total_data_len %d", item_len, total_data_len);
+ if (total_data_len < item_len) {
+ fp_err("corrupted fingerprint data");
+ break;
+ }
+ total_data_len -= item_len;
+
+ item = fpi_print_data_item_new(item_len);
+ /* FIXME: fp_print_data->data content is not endianess agnostic */
+ memcpy(item->data, raw_item->data, item_len);
+ data->prints = g_slist_prepend(data->prints, item);
+
+ raw_buf += sizeof(*raw_item);
+ raw_buf += item_len;
+ }
+
+ if (g_slist_length(data->prints) == 0) {
+ fp_print_data_free(data);
+ data = NULL;
+ }
+
+ return data;
+
+}
+
/** \ingroup print_data
* Load a stored print from a data buffer. The contents of said buffer must
* be the untouched contents of a buffer previously supplied to you by the
@@ -157,24 +257,21 @@ API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
size_t buflen)
{
- struct fpi_print_data_fp1 *raw = (struct fpi_print_data_fp1 *) buf;
- size_t print_data_len;
- struct fp_print_data *data;
+ struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
fp_dbg("buffer size %zd", buflen);
if (buflen < sizeof(*raw))
return NULL;
- if (strncmp(raw->prefix, "FP1", 3) != 0) {
+ if (strncmp(raw->prefix, "FP1", 3) == 0) {
+ return fpi_print_data_from_fp1_data(buf, buflen);
+ } else if (strncmp(raw->prefix, "FP2", 3) == 0) {
+ return fpi_print_data_from_fp2_data(buf, buflen);
+ } else {
fp_dbg("bad header prefix");
- return NULL;
}
- print_data_len = buflen - sizeof(*raw);
- data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
- GUINT32_FROM_LE(raw->devtype), raw->data_type, print_data_len);
- memcpy(data->data, raw->data, print_data_len);
- return data;
+ return NULL;
}
static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype)
@@ -405,6 +502,8 @@ API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
*/
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
{
+ if (data)
+ g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free);
g_free(data);
}
diff --git a/libfprint/drivers/upeke2.c b/libfprint/drivers/upeke2.c
index 83fe93f..f685205 100644
--- a/libfprint/drivers/upeke2.c
+++ b/libfprint/drivers/upeke2.c
@@ -1072,6 +1072,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
size_t data_len)
{
struct fp_print_data *fdata = NULL;
+ struct fp_print_data_item *item = NULL;
int result = -EPROTO;
if (data_len < sizeof(scan_comp)) {
@@ -1080,9 +1081,11 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
fp_err("unrecognised data prefix %x %x %x %x %x",
data[0], data[1], data[2], data[3], data[4]);
} else {
- fdata = fpi_print_data_new(dev, data_len - sizeof(scan_comp));
- memcpy(fdata->data, data + sizeof(scan_comp),
+ fdata = fpi_print_data_new(dev);
+ item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
+ memcpy(item->data, data + sizeof(scan_comp),
data_len - sizeof(scan_comp));
+ fdata->prints = g_slist_prepend(fdata->prints, item);
result = FP_ENROLL_COMPLETE;
}
@@ -1244,12 +1247,13 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
break;
case VERIFY_INIT: ;
struct fp_print_data *print = dev->verify_data;
- size_t data_len = sizeof(verify_hdr) + print->length;
+ struct fp_print_data_item *item = print->prints->data;
+ size_t data_len = sizeof(verify_hdr) + item->length;
unsigned char *data = g_malloc(data_len);
struct libusb_transfer *transfer;
memcpy(data, verify_hdr, sizeof(verify_hdr));
- memcpy(data + sizeof(verify_hdr), print->data, print->length);
+ memcpy(data + sizeof(verify_hdr), item->data, item->length);
transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len,
verify_init_2803_cb, ssm);
g_free(data);
diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c
index b347949..c191a2d 100644
--- a/libfprint/drivers/upekts.c
+++ b/libfprint/drivers/upekts.c
@@ -1077,6 +1077,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
size_t data_len)
{
struct fp_print_data *fdata = NULL;
+ struct fp_print_data_item *item = NULL;
int result = -EPROTO;
if (data_len < sizeof(scan_comp)) {
@@ -1085,9 +1086,11 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
fp_err("unrecognised data prefix %x %x %x %x %x",
data[0], data[1], data[2], data[3], data[4]);
} else {
- fdata = fpi_print_data_new(dev, data_len - sizeof(scan_comp));
- memcpy(fdata->data, data + sizeof(scan_comp),
+ fdata = fpi_print_data_new(dev);
+ item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
+ memcpy(item->data, data + sizeof(scan_comp),
data_len - sizeof(scan_comp));
+ fdata->prints = g_slist_prepend(fdata->prints, item);
result = FP_ENROLL_COMPLETE;
}
@@ -1249,12 +1252,13 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
break;
case VERIFY_INIT: ;
struct fp_print_data *print = dev->verify_data;
- size_t data_len = sizeof(verify_hdr) + print->length;
+ struct fp_print_data_item *item = print->prints->data;
+ size_t data_len = sizeof(verify_hdr) + item->length;
unsigned char *data = g_malloc(data_len);
struct libusb_transfer *transfer;
memcpy(data, verify_hdr, sizeof(verify_hdr));
- memcpy(data + sizeof(verify_hdr), print->data, print->length);
+ memcpy(data + sizeof(verify_hdr), item->data, item->length);
transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len,
verify_init_2803_cb, ssm);
g_free(data);
diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h
index 42d38f1..8af0282 100644
--- a/libfprint/fp_internal.h
+++ b/libfprint/fp_internal.h
@@ -179,7 +179,9 @@ struct fp_img_dev {
int action_state;
struct fp_print_data *acquire_data;
+ struct fp_print_data *enroll_data;
struct fp_img *acquire_img;
+ int enroll_stage;
int action_result;
/* FIXME: better place to put this? */
@@ -325,15 +327,19 @@ enum fp_print_data_type {
PRINT_DATA_NBIS_MINUTIAE,
};
+struct fp_print_data_item {
+ size_t length;
+ unsigned char data[0];
+};
+
struct fp_print_data {
uint16_t driver_id;
uint32_t devtype;
enum fp_print_data_type type;
- size_t length;
- unsigned char data[0];
+ GSList *prints;
};
-struct fpi_print_data_fp1 {
+struct fpi_print_data_fp2 {
char prefix[3];
uint16_t driver_id;
uint32_t devtype;
@@ -341,8 +347,14 @@ struct fpi_print_data_fp1 {
unsigned char data[0];
} __attribute__((__packed__));
+struct fpi_print_data_item_fp2 {
+ uint32_t length;
+ unsigned char data[0];
+} __attribute__((__packed__));
+
void fpi_data_exit(void);
-struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length);
+struct fp_print_data *fpi_print_data_new(struct fp_dev *dev);
+struct fp_print_data_item *fpi_print_data_item_new(size_t length);
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
enum fp_print_data_type type2);
diff --git a/libfprint/img.c b/libfprint/img.c
index b1d32ed..3c91d93 100644
--- a/libfprint/img.c
+++ b/libfprint/img.c
@@ -313,6 +313,7 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
struct fp_print_data **ret)
{
struct fp_print_data *print;
+ struct fp_print_data_item *item;
int r;
if (!img->minutiae) {
@@ -327,9 +328,11 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
/* FIXME: space is wasted if we dont hit the max minutiae count. would
* be good to make this dynamic. */
- print = fpi_print_data_new(imgdev->dev, sizeof(struct xyt_struct));
+ print = fpi_print_data_new(imgdev->dev);
+ item = fpi_print_data_item_new(sizeof(struct xyt_struct));
print->type = PRINT_DATA_NBIS_MINUTIAE;
- minutiae_to_xyt(img->minutiae, img->width, img->height, print->data);
+ minutiae_to_xyt(img->minutiae, img->width, img->height, item->data);
+ print->prints = g_slist_prepend(print->prints, item);
/* FIXME: the print buffer at this point is endian-specific, and will
* only work when loaded onto machines with identical endianness. not good!
@@ -342,42 +345,73 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
struct fp_print_data *new_print)
{
- struct xyt_struct *gstruct = (struct xyt_struct *) enrolled_print->data;
- struct xyt_struct *pstruct = (struct xyt_struct *) new_print->data;
- GTimer *timer;
- int r;
+ int score, max_score = 0, probe_len;
+ struct xyt_struct *pstruct = NULL;
+ struct xyt_struct *gstruct = NULL;
+ struct fp_print_data_item *data_item;
+ GSList *list_item;
if (enrolled_print->type != PRINT_DATA_NBIS_MINUTIAE ||
- new_print->type != PRINT_DATA_NBIS_MINUTIAE) {
+ new_print->type != PRINT_DATA_NBIS_MINUTIAE) {
fp_err("invalid print format");
return -EINVAL;
}
- timer = g_timer_new();
- r = bozorth_main(pstruct, gstruct);
- g_timer_stop(timer);
- fp_dbg("bozorth processing took %f seconds, score=%d",
- g_timer_elapsed(timer, NULL), r);
- g_timer_destroy(timer);
+ if (g_slist_length(new_print->prints) != 1) {
+ fp_err("new_print contains more than one sample, is it enrolled print?");
+ return -EINVAL;
+ }
- return r;
+ data_item = new_print->prints->data;
+ pstruct = (struct xyt_struct *)data_item->data;
+
+ probe_len = bozorth_probe_init(pstruct);
+ list_item = enrolled_print->prints;
+ do {
+ data_item = list_item->data;
+ gstruct = (struct xyt_struct *)data_item->data;
+ score = bozorth_to_gallery(probe_len, pstruct, gstruct);
+ fp_dbg("score %d", score);
+ max_score = max(score, max_score);
+ list_item = g_slist_next(list_item);
+ } while (list_item);
+
+ return max_score;
}
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
struct fp_print_data **gallery, int match_threshold, size_t *match_offset)
{
- struct xyt_struct *pstruct = (struct xyt_struct *) print->data;
+ struct xyt_struct *pstruct;
+ struct xyt_struct *gstruct;
struct fp_print_data *gallery_print;
- int probe_len = bozorth_probe_init(pstruct);
+ struct fp_print_data_item *data_item;
+ int probe_len;
size_t i = 0;
+ int r;
+ GSList *list_item;
+
+ if (g_slist_length(print->prints) != 1) {
+ fp_err("new_print contains more than one sample, is it enrolled print?");
+ return -EINVAL;
+ }
+
+ data_item = print->prints->data;
+ pstruct = (struct xyt_struct *)data_item->data;
+ probe_len = bozorth_probe_init(pstruct);
while ((gallery_print = gallery[i++])) {
- struct xyt_struct *gstruct = (struct xyt_struct *) gallery_print->data;
- int r = bozorth_to_gallery(probe_len, pstruct, gstruct);
- if (r >= match_threshold) {
- *match_offset = i - 1;
- return FP_VERIFY_MATCH;
- }
+ list_item = gallery_print->prints;
+ do {
+ data_item = list_item->data;
+ gstruct = (struct xyt_struct *)data_item->data;
+ r = bozorth_to_gallery(probe_len, pstruct, gstruct);
+ if (r >= match_threshold) {
+ *match_offset = i - 1;
+ return FP_VERIFY_MATCH;
+ }
+ list_item = g_slist_next(list_item);
+ } while (list_item);
}
return FP_VERIFY_NO_MATCH;
}
diff --git a/libfprint/imgdev.c b/libfprint/imgdev.c
index f83ea11..f960ee3 100644
--- a/libfprint/imgdev.c
+++ b/libfprint/imgdev.c
@@ -25,6 +25,7 @@
#define MIN_ACCEPTABLE_MINUTIAE 10
#define BOZORTH3_DEFAULT_THRESHOLD 40
+#define IMG_ENROLL_STAGES 5
static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
{
@@ -33,8 +34,9 @@ static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
int r = 0;
imgdev->dev = dev;
+ imgdev->enroll_stage = 0;
dev->priv = imgdev;
- dev->nr_enroll_stages = 1;
+ dev->nr_enroll_stages = IMG_ENROLL_STAGES;
/* for consistency in driver code, allow udev access through imgdev */
imgdev->udev = dev->udev;
@@ -144,7 +146,13 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
switch (imgdev->action) {
case IMG_ACTION_ENROLL:
fp_dbg("reporting enroll result");
- fpi_drvcb_enroll_stage_completed(imgdev->dev, r, data, img);
+ data = imgdev->enroll_data;
+ if (r == FP_ENROLL_COMPLETE) {
+ imgdev->enroll_data = NULL;
+ }
+ fpi_drvcb_enroll_stage_completed(imgdev->dev, r,
+ r == FP_ENROLL_COMPLETE ? data : NULL,
+ img);
/* the callback can cancel enrollment, so recheck current
* action and the status to see if retry is needed */
if (imgdev->action == IMG_ACTION_ENROLL &&
@@ -253,7 +261,22 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
imgdev->acquire_data = print;
switch (imgdev->action) {
case IMG_ACTION_ENROLL:
- imgdev->action_result = FP_ENROLL_COMPLETE;
+ if (!imgdev->enroll_data) {
+ imgdev->enroll_data = fpi_print_data_new(imgdev->dev);
+ }
+ BUG_ON(g_slist_length(print->prints) != 1);
+ /* Move print data from acquire data into enroll_data */
+ imgdev->enroll_data->prints =
+ g_slist_prepend(imgdev->enroll_data->prints, print->prints->data);
+ print->prints = g_slist_remove(print->prints, print->prints->data);
+
+ fp_print_data_free(imgdev->acquire_data);
+ imgdev->acquire_data = NULL;
+ imgdev->enroll_stage++;
+ if (imgdev->enroll_stage == imgdev->dev->nr_enroll_stages)
+ imgdev->action_result = FP_ENROLL_COMPLETE;
+ else
+ imgdev->action_result = FP_ENROLL_PASS;
break;
case IMG_ACTION_VERIFY:
verify_process_img(imgdev);
@@ -402,6 +425,7 @@ static int generic_acquire_start(struct fp_dev *dev, int action)
fp_dbg("action %d", action);
imgdev->action = action;
imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING;
+ imgdev->enroll_stage = 0;
r = dev_activate(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
if (r < 0)
@@ -417,8 +441,10 @@ static void generic_acquire_stop(struct fp_img_dev *imgdev)
dev_deactivate(imgdev);
fp_print_data_free(imgdev->acquire_data);
+ fp_print_data_free(imgdev->enroll_data);
fp_img_free(imgdev->acquire_img);
imgdev->acquire_data = NULL;
+ imgdev->enroll_data = NULL;
imgdev->acquire_img = NULL;
imgdev->action_result = 0;
}