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:
parent
5b20892dd4
commit
8c5f2e6434
5 changed files with 144 additions and 356 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue