aes: unify image processing code for AuthenTec devices

Move overlap detection and assembling code into aeslib to prevent
code duplication

https://bugs.freedesktop.org/show_bug.cgi?id=57426
This commit is contained in:
Vasily Khoruzhick 2012-11-17 15:32:25 +03:00 committed by Bastien Nocera
parent 5b20892dd4
commit 8c5f2e6434
5 changed files with 144 additions and 356 deletions

View file

@ -20,6 +20,7 @@
#define FP_COMPONENT "aeslib" #define FP_COMPONENT "aeslib"
#include <errno.h> #include <errno.h>
#include <string.h>
#include <libusb.h> #include <libusb.h>
#include <glib.h> #include <glib.h>
@ -171,3 +172,113 @@ void aes_assemble_image(unsigned char *input, size_t width, size_t height,
} }
} }
/* find overlapping parts of frames */
static unsigned int find_overlap(unsigned char *first_frame,
unsigned char *second_frame, unsigned int *min_error,
unsigned int frame_width, unsigned int frame_height)
{
unsigned int dy;
unsigned int not_overlapped_height = 0;
/* 255 is highest brightness value for an 8bpp image */
*min_error = 255 * frame_width * frame_height;
for (dy = 0; dy < frame_height; dy++) {
/* Calculating difference (error) between parts of frames */
unsigned int i;
unsigned int error = 0;
for (i = 0; i < frame_width * (frame_height - dy); i++) {
/* Using ? operator to avoid abs function */
error += first_frame[i] > second_frame[i] ?
(first_frame[i] - second_frame[i]) :
(second_frame[i] - first_frame[i]);
}
/* Normalize error */
error *= 15;
error /= i;
if (error < *min_error) {
*min_error = error;
not_overlapped_height = dy;
}
first_frame += frame_width;
}
return not_overlapped_height;
}
/* assemble a series of frames into a single image */
static unsigned int assemble(GSList *list_entry, size_t num_stripes,
unsigned int frame_width, unsigned int frame_height,
unsigned char *output, gboolean reverse, unsigned int *errors_sum)
{
uint8_t *assembled = output;
int frame;
uint32_t image_height = frame_height;
unsigned int min_error, frame_size = frame_width * frame_height;
*errors_sum = 0;
if (reverse)
output += (num_stripes - 1) * frame_size;
for (frame = 0; frame < num_stripes; frame++) {
aes_assemble_image(list_entry->data, frame_width, frame_height, output);
if (reverse)
output -= frame_size;
else
output += frame_size;
list_entry = g_slist_next(list_entry);
}
/* Detecting where frames overlaped */
output = assembled;
for (frame = 1; frame < num_stripes; frame++) {
int not_overlapped;
output += frame_size;
not_overlapped = find_overlap(assembled, output, &min_error,
frame_width, frame_height);
*errors_sum += min_error;
image_height += not_overlapped;
assembled += frame_width * not_overlapped;
memcpy(assembled, output, frame_size);
}
return image_height;
}
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
unsigned int frame_width, unsigned int frame_height)
{
size_t final_size;
struct fp_img *img;
unsigned int frame_size = frame_width * frame_height;
unsigned int errors_sum, r_errors_sum;
BUG_ON(stripes_len == 0);
/* create buffer big enough for max image */
img = fpi_img_new(stripes_len * frame_size);
img->flags = FP_IMG_COLORS_INVERTED;
img->height = assemble(stripes, stripes_len,
frame_width, frame_height,
img->data, FALSE, &errors_sum);
img->height = assemble(stripes, stripes_len,
frame_width, frame_height,
img->data, TRUE, &r_errors_sum);
if (r_errors_sum > errors_sum) {
img->height = assemble(stripes, stripes_len,
frame_width, frame_height,
img->data, FALSE, &errors_sum);
img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
fp_dbg("normal scan direction");
} else {
fp_dbg("reversed scan direction");
}
/* now that overlap has been removed, resize output image buffer */
final_size = img->height * frame_width;
img = fpi_img_resize(img, final_size);
img->width = frame_width;
return img;
}

View file

@ -36,5 +36,8 @@ void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
void aes_assemble_image(unsigned char *input, size_t width, size_t height, void aes_assemble_image(unsigned char *input, size_t width, size_t height,
unsigned char *output); unsigned char *output);
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
unsigned int frame_width, unsigned int frame_height);
#endif #endif

View file

@ -4,6 +4,7 @@
* Copyright (C) 2007 Cyrille Bagard * Copyright (C) 2007 Cyrille Bagard
* Copyright (C) 2007 Vasily Khoruzhick * Copyright (C) 2007 Vasily Khoruzhick
* Copyright (C) 2009 Guido Grazioli <guido.grazioli@gmail.com> * Copyright (C) 2009 Guido Grazioli <guido.grazioli@gmail.com>
* Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
* *
* Based on code from libfprint aes2501 driver. * Based on code from libfprint aes2501 driver.
* *
@ -147,131 +148,6 @@ static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes)
} }
} }
/****** IMAGE PROCESSING ******/
/* find overlapping parts of frames */
static unsigned int find_overlap(unsigned char *first_frame,
unsigned char *second_frame, unsigned int *min_error)
{
unsigned int dy;
unsigned int not_overlapped_height = 0;
*min_error = 255 * FRAME_SIZE;
for (dy = 0; dy < FRAME_HEIGHT; dy++) {
/* Calculating difference (error) between parts of frames */
unsigned int i;
unsigned int error = 0;
for (i = 0; i < FRAME_WIDTH * (FRAME_HEIGHT - dy); i++) {
/* Using ? operator to avoid abs function */
error += first_frame[i] > second_frame[i] ?
(first_frame[i] - second_frame[i]) :
(second_frame[i] - first_frame[i]);
}
/* Normalize error */
error *= 15;
error /= i;
if (error < *min_error) {
*min_error = error;
not_overlapped_height = dy;
}
first_frame += FRAME_WIDTH;
}
return not_overlapped_height;
}
/* assemble a series of frames into a single image */
static unsigned int assemble(struct aes1610_dev *aesdev, unsigned char *output,
gboolean reverse, unsigned int *errors_sum)
{
uint8_t *assembled = output;
int frame;
uint32_t image_height = FRAME_HEIGHT;
unsigned int min_error;
size_t num_strips = aesdev->strips_len;
GSList *list_entry = aesdev->strips;
*errors_sum = 0;
if (num_strips < 1)
return 0;
/* Rotating given data by 90 degrees
* Taken from document describing aes1610 image format
* TODO: move reversing detection here */
if (reverse)
output += (num_strips - 1) * FRAME_SIZE;
for (frame = 0; frame < num_strips; frame++) {
aes_assemble_image(list_entry->data, FRAME_WIDTH, FRAME_HEIGHT, output);
if (reverse)
output -= FRAME_SIZE;
else
output += FRAME_SIZE;
list_entry = g_slist_next(list_entry);
}
/* Detecting where frames overlaped */
output = assembled;
for (frame = 1; frame < num_strips; frame++) {
int not_overlapped;
output += FRAME_SIZE;
not_overlapped = find_overlap(assembled, output, &min_error);
*errors_sum += min_error;
image_height += not_overlapped;
assembled += FRAME_WIDTH * not_overlapped;
memcpy(assembled, output, FRAME_SIZE);
}
return image_height;
}
static void assemble_and_submit_image(struct fp_img_dev *dev)
{
struct aes1610_dev *aesdev = dev->priv;
size_t final_size;
struct fp_img *img;
unsigned int errors_sum, r_errors_sum;
fp_dbg("");
BUG_ON(aesdev->strips_len == 0);
/* reverse list */
aesdev->strips = g_slist_reverse(aesdev->strips);
/* create buffer big enough for max image */
img = fpi_img_new(aesdev->strips_len * FRAME_SIZE);
img->flags = FP_IMG_COLORS_INVERTED;
img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
img->height = assemble(aesdev, img->data, TRUE, &r_errors_sum);
if (r_errors_sum > errors_sum) {
img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
fp_dbg("normal scan direction");
} else {
fp_dbg("reversed scan direction");
}
/* now that overlap has been removed, resize output image buffer */
final_size = img->height * FRAME_WIDTH;
img = fpi_img_resize(img, final_size);
/* FIXME: ugly workaround */
if (img->height < 12)
img->height = 12;
fpi_imgdev_image_captured(dev, img);
/* free strips and strip list */
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
g_slist_free(aesdev->strips);
aesdev->strips = NULL;
aesdev->strips_len = 0;
aesdev->blanks_count = 0;
}
/****** FINGER PRESENCE DETECTION ******/ /****** FINGER PRESENCE DETECTION ******/
@ -732,11 +608,19 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
/* stop capturing if MAX_FRAMES is reached */ /* stop capturing if MAX_FRAMES is reached */
if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) { if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
struct fp_img *img;
fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips)); fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips));
/* send stop capture bits */ /* send stop capture bits */
aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL); aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
/* assemble image and submit it to library */ aesdev->strips = g_slist_reverse(aesdev->strips);
assemble_and_submit_image(dev); img = aes_assemble(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT);
g_slist_free_full(aesdev->strips, (GFunc) g_free);
aesdev->strips = NULL;
aesdev->strips_len = 0;
aesdev->blanks_count = 0;
fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE); fpi_imgdev_report_finger_status(dev, FALSE);
/* marking machine complete will re-trigger finger detection loop */ /* marking machine complete will re-trigger finger detection loop */
fpi_ssm_mark_completed(ssm); fpi_ssm_mark_completed(ssm);

View file

@ -248,119 +248,6 @@ static int sum_histogram_values(unsigned char *data, uint8_t threshold)
return r; return r;
} }
/* find overlapping parts of frames */
static unsigned int find_overlap(unsigned char *first_frame,
unsigned char *second_frame, unsigned int *min_error)
{
unsigned int dy;
unsigned int not_overlapped_height = 0;
*min_error = 255 * FRAME_SIZE;
for (dy = 0; dy < FRAME_HEIGHT; dy++) {
/* Calculating difference (error) between parts of frames */
unsigned int i;
unsigned int error = 0;
for (i = 0; i < FRAME_WIDTH * (FRAME_HEIGHT - dy); i++) {
/* Using ? operator to avoid abs function */
error += first_frame[i] > second_frame[i] ?
(first_frame[i] - second_frame[i]) :
(second_frame[i] - first_frame[i]);
}
/* Normalize error */
error *= 15;
error /= i;
if (error < *min_error) {
*min_error = error;
not_overlapped_height = dy;
}
first_frame += FRAME_WIDTH;
}
return not_overlapped_height;
}
/* assemble a series of frames into a single image */
static unsigned int assemble(struct aes2501_dev *aesdev, unsigned char *output,
gboolean reverse, unsigned int *errors_sum)
{
uint8_t *assembled = output;
int frame;
uint32_t image_height = FRAME_HEIGHT;
unsigned int min_error;
size_t num_strips = aesdev->strips_len;
GSList *list_entry = aesdev->strips;
*errors_sum = 0;
/* Rotating given data by 90 degrees
* Taken from document describing aes2501 image format
* TODO: move reversing detection here */
if (reverse)
output += (num_strips - 1) * FRAME_SIZE;
for (frame = 0; frame < num_strips; frame++) {
aes_assemble_image(list_entry->data, FRAME_WIDTH, FRAME_HEIGHT, output);
if (reverse)
output -= FRAME_SIZE;
else
output += FRAME_SIZE;
list_entry = g_slist_next(list_entry);
}
/* Detecting where frames overlaped */
output = assembled;
for (frame = 1; frame < num_strips; frame++) {
int not_overlapped;
output += FRAME_SIZE;
not_overlapped = find_overlap(assembled, output, &min_error);
*errors_sum += min_error;
image_height += not_overlapped;
assembled += FRAME_WIDTH * not_overlapped;
memcpy(assembled, output, FRAME_SIZE);
}
return image_height;
}
static void assemble_and_submit_image(struct fp_img_dev *dev)
{
struct aes2501_dev *aesdev = dev->priv;
size_t final_size;
struct fp_img *img;
unsigned int errors_sum, r_errors_sum;
BUG_ON(aesdev->strips_len == 0);
/* reverse list */
aesdev->strips = g_slist_reverse(aesdev->strips);
/* create buffer big enough for max image */
img = fpi_img_new(aesdev->strips_len * FRAME_SIZE);
img->flags = FP_IMG_COLORS_INVERTED;
img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
img->height = assemble(aesdev, img->data, TRUE, &r_errors_sum);
if (r_errors_sum > errors_sum) {
img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
fp_dbg("normal scan direction");
} else {
fp_dbg("reversed scan direction");
}
/* now that overlap has been removed, resize output image buffer */
final_size = img->height * FRAME_WIDTH;
img = fpi_img_resize(img, final_size);
fpi_imgdev_image_captured(dev, img);
/* free strips and strip list */
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
g_slist_free(aesdev->strips);
aesdev->strips = NULL;
}
/****** FINGER PRESENCE DETECTION ******/ /****** FINGER PRESENCE DETECTION ******/
static const struct aes_regwrite finger_det_reqs[] = { static const struct aes_regwrite finger_det_reqs[] = {
@ -593,8 +480,15 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
if (sum == 0) { if (sum == 0) {
aesdev->no_finger_cnt++; aesdev->no_finger_cnt++;
if (aesdev->no_finger_cnt == 3) { if (aesdev->no_finger_cnt == 3) {
/* assemble image and submit it to library */ struct fp_img *img;
assemble_and_submit_image(dev);
aesdev->strips = g_slist_reverse(aesdev->strips);
img = aes_assemble(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT);
g_slist_free_full(aesdev->strips, (GFunc) g_free);
aesdev->strips = NULL;
aesdev->strips_len = 0;
fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE); fpi_imgdev_report_finger_status(dev, FALSE);
/* marking machine complete will re-trigger finger detection loop */ /* marking machine complete will re-trigger finger detection loop */
fpi_ssm_mark_completed(ssm); fpi_ssm_mark_completed(ssm);

View file

@ -64,119 +64,6 @@ struct aes2550_dev {
int heartbeat_cnt; int heartbeat_cnt;
}; };
/****** IMAGE PROCESSING ******/
/* find overlapping parts of frames */
static unsigned int find_overlap(unsigned char *first_frame,
unsigned char *second_frame, unsigned int *min_error)
{
unsigned int dy;
unsigned int not_overlapped_height = 0;
/* 255 is highest brightness value for an 8bpp image */
*min_error = 255 * FRAME_SIZE;
for (dy = 0; dy < FRAME_HEIGHT; dy++) {
/* Calculating difference (error) between parts of frames */
unsigned int i;
unsigned int error = 0;
for (i = 0; i < FRAME_WIDTH * (FRAME_HEIGHT - dy); i++) {
/* Using ? operator to avoid abs function */
error += first_frame[i] > second_frame[i] ?
(first_frame[i] - second_frame[i]) :
(second_frame[i] - first_frame[i]);
}
/* Normalize error */
error *= 15;
error /= i;
if (error < *min_error) {
*min_error = error;
not_overlapped_height = dy;
}
first_frame += FRAME_WIDTH;
}
return not_overlapped_height;
}
/* assemble a series of frames into a single image */
static unsigned int assemble(struct aes2550_dev *aesdev, unsigned char *output,
gboolean reverse, unsigned int *errors_sum)
{
uint8_t *assembled = output;
int frame;
uint32_t image_height = FRAME_HEIGHT;
unsigned int min_error;
size_t num_strips = aesdev->strips_len;
GSList *list_entry = aesdev->strips;
*errors_sum = 0;
if (reverse)
output += (num_strips - 1) * FRAME_SIZE;
for (frame = 0; frame < num_strips; frame++) {
aes_assemble_image(list_entry->data, FRAME_WIDTH, FRAME_HEIGHT, output);
if (reverse)
output -= FRAME_SIZE;
else
output += FRAME_SIZE;
list_entry = g_slist_next(list_entry);
}
/* Detecting where frames overlaped */
output = assembled;
for (frame = 1; frame < num_strips; frame++) {
int not_overlapped;
output += FRAME_SIZE;
not_overlapped = find_overlap(assembled, output, &min_error);
*errors_sum += min_error;
image_height += not_overlapped;
assembled += FRAME_WIDTH * not_overlapped;
memcpy(assembled, output, FRAME_SIZE);
}
return image_height;
}
static void assemble_and_submit_image(struct fp_img_dev *dev)
{
struct aes2550_dev *aesdev = dev->priv;
size_t final_size;
struct fp_img *img;
unsigned int errors_sum, r_errors_sum;
BUG_ON(aesdev->strips_len == 0);
/* reverse list */
aesdev->strips = g_slist_reverse(aesdev->strips);
/* create buffer big enough for max image */
img = fpi_img_new(aesdev->strips_len * FRAME_SIZE);
img->flags = FP_IMG_COLORS_INVERTED;
img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
img->height = assemble(aesdev, img->data, TRUE, &r_errors_sum);
if (r_errors_sum > errors_sum) {
img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
fp_dbg("normal scan direction");
} else {
fp_dbg("reversed scan direction");
}
/* now that overlap has been removed, resize output image buffer */
final_size = img->height * FRAME_WIDTH;
img = fpi_img_resize(img, final_size);
fpi_imgdev_image_captured(dev, img);
/* free strips and strip list */
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
g_slist_free(aesdev->strips);
aesdev->strips = NULL;
aesdev->strips_len = 0;
}
/****** FINGER PRESENCE DETECTION ******/ /****** FINGER PRESENCE DETECTION ******/
static unsigned char finger_det_reqs[] = { static unsigned char finger_det_reqs[] = {
@ -356,10 +243,19 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
{ {
struct fpi_ssm *ssm = transfer->user_data; struct fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct aes2550_dev *aesdev = dev->priv;
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
(transfer->length == transfer->actual_length)) { (transfer->length == transfer->actual_length)) {
assemble_and_submit_image(dev); struct fp_img *img;
aesdev->strips = g_slist_reverse(aesdev->strips);
img = aes_assemble(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT);
g_slist_free_full(aesdev->strips, (GFunc) g_free);
aesdev->strips = NULL;
aesdev->strips_len = 0;
fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE); fpi_imgdev_report_finger_status(dev, FALSE);
/* marking machine complete will re-trigger finger detection loop */ /* marking machine complete will re-trigger finger detection loop */
fpi_ssm_mark_completed(ssm); fpi_ssm_mark_completed(ssm);