mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2025-11-15 07:38:12 +00:00
aeslib: improve frame-assembling routines
Some scanners provide hardware assistance in frame assemling, i.e. horizontal and vertical offset to previous frame is provided. This commit improves code to utilise that assistance. Sensors without hardware assistance will use software algorithm, which was also improved to do search in horizontal direction.
This commit is contained in:
@@ -609,13 +609,24 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||
/* stop capturing if MAX_FRAMES is reached */
|
||||
if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
|
||||
struct fp_img *img;
|
||||
unsigned int height, rev_height;
|
||||
|
||||
fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips));
|
||||
/* send stop capture bits */
|
||||
aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
|
||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
||||
rev_height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT, TRUE);
|
||||
fp_dbg("heights: %d rev: %d", height, rev_height);
|
||||
if (rev_height < height) {
|
||||
fp_dbg("Reversed direction");
|
||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
||||
}
|
||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT);
|
||||
FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
|
||||
g_slist_free_full(aesdev->strips, g_free);
|
||||
aesdev->strips = NULL;
|
||||
aesdev->strips_len = 0;
|
||||
@@ -829,13 +840,9 @@ struct fp_img_driver aes1610_driver = {
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = -1,
|
||||
.img_width = 128,
|
||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||
|
||||
/* temporarily lowered until we sort out image processing code
|
||||
* binarized scan quality is good, minutiae detection is accurate,
|
||||
* it's just that we get fewer minutiae than other scanners (less scanning
|
||||
* area) */
|
||||
.bz3_threshold = 10,
|
||||
.bz3_threshold = 50,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
|
||||
@@ -49,7 +49,6 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||
aesdev->h_scale_factor = SCALE_FACTOR;
|
||||
aesdev->init_seqs[0] = aes1660_init_1;
|
||||
aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1);
|
||||
aesdev->init_seqs[1] = aes1660_init_2;
|
||||
@@ -102,7 +101,8 @@ struct fp_img_driver aes1660_driver = {
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = -1,
|
||||
.img_width = FRAME_WIDTH * SCALE_FACTOR,
|
||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||
.bz3_threshold = 70,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
|
||||
@@ -481,10 +481,21 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||
aesdev->no_finger_cnt++;
|
||||
if (aesdev->no_finger_cnt == 3) {
|
||||
struct fp_img *img;
|
||||
unsigned int height, rev_height;
|
||||
|
||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
||||
rev_height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT, TRUE);
|
||||
fp_dbg("heights: %d rev: %d", height, rev_height);
|
||||
if (rev_height < height) {
|
||||
fp_dbg("Reversed direction");
|
||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
||||
}
|
||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT);
|
||||
FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
|
||||
g_slist_free_full(aesdev->strips, g_free);
|
||||
aesdev->strips = NULL;
|
||||
aesdev->strips_len = 0;
|
||||
@@ -498,10 +509,13 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||
} else {
|
||||
/* obtain next strip */
|
||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
||||
stripdata = g_malloc(192 * 8);
|
||||
struct aes_stripe *stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe));
|
||||
stripe->delta_x = 0;
|
||||
stripe->delta_y = 0;
|
||||
stripdata = stripe->data;
|
||||
memcpy(stripdata, data + 1, 192*8);
|
||||
aesdev->no_finger_cnt = 0;
|
||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata);
|
||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||
aesdev->strips_len++;
|
||||
|
||||
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
||||
@@ -867,7 +881,7 @@ struct fp_img_driver aes2501_driver = {
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = -1,
|
||||
.img_width = 192,
|
||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
|
||||
@@ -204,6 +204,7 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||
unsigned char *stripdata;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
struct aes_stripe *stripe;
|
||||
int len;
|
||||
|
||||
if (data[0] != AES2550_EDATA_MAGIC) {
|
||||
@@ -214,11 +215,16 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||
if (len != (AES2550_STRIP_SIZE - 3)) {
|
||||
fp_dbg("Bogus frame len: %.4x\n", len);
|
||||
}
|
||||
stripdata = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2); /* 4 bits per pixel */
|
||||
stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe)); /* 4 bits per pixel */
|
||||
stripe->delta_x = (int8_t)data[6];
|
||||
stripe->delta_y = -(int8_t)data[7];
|
||||
stripdata = stripe->data;
|
||||
memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
|
||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata);
|
||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||
aesdev->strips_len++;
|
||||
|
||||
fp_dbg("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -242,12 +248,13 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
(transfer->length == transfer->actual_length) &&
|
||||
aesdev->strips_len) {
|
||||
struct fp_img *img;
|
||||
|
||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
||||
FRAME_WIDTH, FRAME_HEIGHT);
|
||||
FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
|
||||
g_slist_free_full(aesdev->strips, g_free);
|
||||
aesdev->strips = NULL;
|
||||
aesdev->strips_len = 0;
|
||||
@@ -637,7 +644,7 @@ struct fp_img_driver aes2550_driver = {
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = -1,
|
||||
.img_width = 192,
|
||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
|
||||
@@ -49,7 +49,6 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||
/* No scaling for AES2660 */
|
||||
aesdev->h_scale_factor = 1;
|
||||
aesdev->init_seqs[0] = aes2660_init_1;
|
||||
aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1);
|
||||
aesdev->init_seqs[1] = aes2660_init_2;
|
||||
@@ -103,7 +102,7 @@ struct fp_img_driver aes2660_driver = {
|
||||
},
|
||||
.flags = 0,
|
||||
.img_height = -1,
|
||||
.img_width = FRAME_WIDTH,
|
||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
|
||||
@@ -52,6 +52,20 @@
|
||||
|
||||
static void do_capture(struct fp_img_dev *dev);
|
||||
|
||||
static void aes3k_assemble_image(unsigned char *input, size_t width, size_t height,
|
||||
unsigned char *output)
|
||||
{
|
||||
size_t row, column;
|
||||
|
||||
for (column = 0; column < width; column++) {
|
||||
for (row = 0; row < height; row += 2) {
|
||||
output[width * row + column] = (*input & 0x0f) * 17;
|
||||
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
||||
input++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void img_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fp_img_dev *dev = transfer->user_data;
|
||||
@@ -80,7 +94,7 @@ static void img_cb(struct libusb_transfer *transfer)
|
||||
for (i = 0; i < aesdev->frame_number; i++) {
|
||||
fp_dbg("frame header byte %02x", *ptr);
|
||||
ptr++;
|
||||
aes_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT));
|
||||
aes3k_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT));
|
||||
ptr += aesdev->frame_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -273,19 +273,25 @@ enum capture_states {
|
||||
/* Returns number of processed bytes */
|
||||
static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||
{
|
||||
struct aes_stripe *stripe;
|
||||
unsigned char *stripdata;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
|
||||
stripdata = g_malloc(aesdev->frame_width * FRAME_HEIGHT / 2); /* 4 bits per pixel */
|
||||
stripe = g_malloc(aesdev->frame_width * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe)); /* 4 bpp */
|
||||
stripdata = stripe->data;
|
||||
|
||||
fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET],
|
||||
data[AESX660_LAST_FRAME_OFFSET]);
|
||||
|
||||
stripe->delta_x = (int8_t)data[AESX660_FRAME_DELTA_X_OFFSET];
|
||||
stripe->delta_y = -(int8_t)data[AESX660_FRAME_DELTA_Y_OFFSET];
|
||||
fp_dbg("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y);
|
||||
|
||||
if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) {
|
||||
memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->frame_width * FRAME_HEIGHT / 2);
|
||||
|
||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata);
|
||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||
aesdev->strips_len++;
|
||||
return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT);
|
||||
} else {
|
||||
@@ -302,22 +308,15 @@ static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
struct fp_img *img, *tmp;
|
||||
struct fp_img *img;
|
||||
|
||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||
tmp = aes_assemble(aesdev->strips, aesdev->strips_len,
|
||||
aesdev->frame_width, FRAME_HEIGHT);
|
||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
||||
aesdev->frame_width, FRAME_HEIGHT, aesdev->frame_width + aesdev->frame_width / 2);
|
||||
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
|
||||
g_slist_free(aesdev->strips);
|
||||
aesdev->strips = NULL;
|
||||
aesdev->strips_len = 0;
|
||||
if (aesdev->h_scale_factor > 1) {
|
||||
img = fpi_im_resize(tmp, aesdev->h_scale_factor, 1);
|
||||
fp_img_free(tmp);
|
||||
} else {
|
||||
img = tmp;
|
||||
tmp = NULL;
|
||||
}
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#define AESX660_LAST_FRAME_OFFSET 0x04
|
||||
#define AESX660_LAST_FRAME_BIT 0x01
|
||||
|
||||
#define AESX660_FRAME_DELTA_X_OFFSET 16
|
||||
#define AESX660_FRAME_DELTA_Y_OFFSET 17
|
||||
|
||||
#define AESX660_IMAGE_OFFSET 43
|
||||
#define AESX660_BULK_TRANSFER_SIZE 4096
|
||||
|
||||
|
||||
Reference in New Issue
Block a user