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:
parent
82ae7c1c09
commit
061a457658
10 changed files with 320 additions and 129 deletions
|
@ -158,127 +158,268 @@ void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||||
continue_write_regv(wdata);
|
continue_write_regv(wdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void aes_assemble_image(unsigned char *input, size_t width, size_t height,
|
static inline unsigned char aes_get_pixel(struct aes_stripe *frame,
|
||||||
unsigned char *output)
|
unsigned int x,
|
||||||
|
unsigned int y,
|
||||||
|
unsigned int frame_width,
|
||||||
|
unsigned int frame_height)
|
||||||
{
|
{
|
||||||
size_t row, column;
|
unsigned char ret;
|
||||||
|
|
||||||
for (column = 0; column < width; column++) {
|
ret = frame->data[x * (frame_height >> 1) + (y >> 1)];
|
||||||
for (row = 0; row < height; row += 2) {
|
ret = y % 2 ? ret >> 4 : ret & 0xf;
|
||||||
output[width * row + column] = (*input & 0x0f) * 17;
|
ret *= 17;
|
||||||
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
|
||||||
input++;
|
return ret;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find overlapping parts of frames */
|
static unsigned int calc_error(struct aes_stripe *first_frame,
|
||||||
static unsigned int find_overlap(unsigned char *first_frame,
|
struct aes_stripe *second_frame,
|
||||||
unsigned char *second_frame, unsigned int *min_error,
|
int dx,
|
||||||
unsigned int frame_width, unsigned int frame_height)
|
int dy,
|
||||||
|
unsigned int frame_width,
|
||||||
|
unsigned int frame_height)
|
||||||
{
|
{
|
||||||
unsigned int dy;
|
unsigned int width, height;
|
||||||
unsigned int not_overlapped_height = 0;
|
unsigned int x1, y1, x2, y2, err, i, j;
|
||||||
/* 255 is highest brightness value for an 8bpp image */
|
|
||||||
*min_error = 255 * frame_width * frame_height;
|
width = frame_width - (dx > 0 ? dx : -dx);
|
||||||
for (dy = 0; dy < frame_height; dy++) {
|
height = frame_height - dy;
|
||||||
/* Calculating difference (error) between parts of frames */
|
|
||||||
unsigned int i;
|
y1 = 0;
|
||||||
unsigned int error = 0;
|
y2 = dy;
|
||||||
for (i = 0; i < frame_width * (frame_height - dy); i++) {
|
i = 0;
|
||||||
/* Using ? operator to avoid abs function */
|
err = 0;
|
||||||
error += first_frame[i] > second_frame[i] ?
|
do {
|
||||||
(first_frame[i] - second_frame[i]) :
|
x1 = dx < 0 ? 0 : dx;
|
||||||
(second_frame[i] - first_frame[i]);
|
x2 = dx < 0 ? -dx : 0;
|
||||||
}
|
j = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned char v1, v2;
|
||||||
|
|
||||||
|
|
||||||
|
v1 = aes_get_pixel(first_frame, x1, y1, frame_width, frame_height);
|
||||||
|
v2 = aes_get_pixel(second_frame, x2, y2, frame_width, frame_height);
|
||||||
|
err += v1 > v2 ? v1 - v2 : v2 - v1;
|
||||||
|
j++;
|
||||||
|
x1++;
|
||||||
|
x2++;
|
||||||
|
|
||||||
|
} while (j < width);
|
||||||
|
i++;
|
||||||
|
y1++;
|
||||||
|
y2++;
|
||||||
|
} while (i < height);
|
||||||
|
|
||||||
/* Normalize error */
|
/* Normalize error */
|
||||||
error *= 15;
|
err *= (frame_height * frame_width);
|
||||||
error /= i;
|
err /= (height * width);
|
||||||
if (error < *min_error) {
|
|
||||||
*min_error = error;
|
|
||||||
not_overlapped_height = dy;
|
|
||||||
}
|
|
||||||
first_frame += frame_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
return not_overlapped_height;
|
if (err == 0)
|
||||||
|
return INT_MAX;
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assemble a series of frames into a single image */
|
/* This function is rather CPU-intensive. It's better to use hardware
|
||||||
static unsigned int assemble(GSList *list_entry, size_t num_stripes,
|
* to detect movement direction when possible.
|
||||||
unsigned int frame_width, unsigned int frame_height,
|
*/
|
||||||
unsigned char *output, gboolean reverse, unsigned int *errors_sum)
|
static void find_overlap(struct aes_stripe *first_frame,
|
||||||
|
struct aes_stripe *second_frame,
|
||||||
|
unsigned int *min_error,
|
||||||
|
unsigned int frame_width,
|
||||||
|
unsigned int frame_height)
|
||||||
{
|
{
|
||||||
uint8_t *assembled = output;
|
int dx, dy;
|
||||||
int frame;
|
unsigned int err;
|
||||||
uint32_t image_height = frame_height;
|
*min_error = INT_MAX;
|
||||||
unsigned int min_error, frame_size = frame_width * frame_height;
|
|
||||||
*errors_sum = 0;
|
|
||||||
|
|
||||||
if (reverse)
|
/* Seeking in horizontal and vertical dimensions,
|
||||||
output += (num_stripes - 1) * frame_size;
|
* for horizontal dimension we'll check only 8 pixels
|
||||||
for (frame = 0; frame < num_stripes; frame++) {
|
* in both directions. For vertical direction diff is
|
||||||
aes_assemble_image(list_entry->data, frame_width, frame_height, output);
|
* rarely less than 2, so start with it.
|
||||||
|
*/
|
||||||
|
for (dy = 2; dy < frame_height; dy++) {
|
||||||
|
for (dx = -8; dx < 8; dx++) {
|
||||||
|
err = calc_error(first_frame, second_frame,
|
||||||
|
dx, dy, frame_width, frame_height);
|
||||||
|
if (err < *min_error) {
|
||||||
|
*min_error = err;
|
||||||
|
second_frame->delta_x = -dx;
|
||||||
|
second_frame->delta_y = dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int aes_calc_delta(GSList *stripes, size_t num_stripes,
|
||||||
|
unsigned int frame_width, unsigned int frame_height,
|
||||||
|
gboolean reverse)
|
||||||
|
{
|
||||||
|
GSList *list_entry = stripes;
|
||||||
|
GTimer *timer;
|
||||||
|
int frame = 1;
|
||||||
|
int height = 0;
|
||||||
|
struct aes_stripe *prev_stripe = list_entry->data;
|
||||||
|
unsigned int min_error;
|
||||||
|
|
||||||
if (reverse)
|
|
||||||
output -= frame_size;
|
|
||||||
else
|
|
||||||
output += frame_size;
|
|
||||||
list_entry = g_slist_next(list_entry);
|
list_entry = g_slist_next(list_entry);
|
||||||
}
|
|
||||||
|
|
||||||
/* Detecting where frames overlaped */
|
timer = g_timer_new();
|
||||||
output = assembled;
|
do {
|
||||||
for (frame = 1; frame < num_stripes; frame++) {
|
struct aes_stripe *cur_stripe = list_entry->data;
|
||||||
int not_overlapped;
|
|
||||||
|
|
||||||
output += frame_size;
|
if (reverse) {
|
||||||
not_overlapped = find_overlap(assembled, output, &min_error,
|
find_overlap(prev_stripe, cur_stripe, &min_error,
|
||||||
frame_width, frame_height);
|
frame_width, frame_height);
|
||||||
*errors_sum += min_error;
|
prev_stripe->delta_y = -prev_stripe->delta_y;
|
||||||
image_height += not_overlapped;
|
prev_stripe->delta_x = -prev_stripe->delta_x;
|
||||||
assembled += frame_width * not_overlapped;
|
}
|
||||||
memcpy(assembled, output, frame_size);
|
else
|
||||||
|
find_overlap(cur_stripe, prev_stripe, &min_error,
|
||||||
|
frame_width, frame_height);
|
||||||
|
|
||||||
|
frame++;
|
||||||
|
height += prev_stripe->delta_y;
|
||||||
|
prev_stripe = cur_stripe;
|
||||||
|
list_entry = g_slist_next(list_entry);
|
||||||
|
|
||||||
|
} while (frame < num_stripes);
|
||||||
|
|
||||||
|
if (height < 0)
|
||||||
|
height = -height;
|
||||||
|
height += frame_height;
|
||||||
|
g_timer_stop(timer);
|
||||||
|
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
|
||||||
|
g_timer_destroy(timer);
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void aes_blit_stripe(struct fp_img *img,
|
||||||
|
struct aes_stripe *stripe,
|
||||||
|
int x, int y, unsigned int frame_width,
|
||||||
|
unsigned int frame_height)
|
||||||
|
{
|
||||||
|
unsigned int ix, iy;
|
||||||
|
unsigned int fx, fy;
|
||||||
|
unsigned int width, height;
|
||||||
|
|
||||||
|
/* Find intersection */
|
||||||
|
if (x < 0) {
|
||||||
|
width = frame_width + x;
|
||||||
|
ix = 0;
|
||||||
|
fx = -x;
|
||||||
|
} else {
|
||||||
|
ix = x;
|
||||||
|
fx = 0;
|
||||||
|
width = frame_width;
|
||||||
|
}
|
||||||
|
if ((ix + width) > img->width)
|
||||||
|
width = img->width - ix;
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
iy = 0;
|
||||||
|
fy = -y;
|
||||||
|
height = frame_height + y;
|
||||||
|
} else {
|
||||||
|
iy = y;
|
||||||
|
fy = 0;
|
||||||
|
height = frame_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fx > frame_width)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fy > frame_height)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ix > img->width)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (iy > img->height)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((iy + height) > img->height)
|
||||||
|
height = img->height - iy;
|
||||||
|
|
||||||
|
for (; fy < height; fy++, iy++) {
|
||||||
|
if (x < 0) {
|
||||||
|
ix = 0;
|
||||||
|
fx = -x;
|
||||||
|
} else {
|
||||||
|
ix = x;
|
||||||
|
fx = 0;
|
||||||
|
}
|
||||||
|
for (; fx < width; fx++, ix++) {
|
||||||
|
img->data[ix + (iy * img->width)] = aes_get_pixel(stripe, fx, fy, frame_width, frame_height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return image_height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
|
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
|
||||||
unsigned int frame_width, unsigned int frame_height)
|
unsigned int frame_width, unsigned int frame_height, unsigned int img_width)
|
||||||
{
|
{
|
||||||
size_t final_size;
|
GSList *stripe;
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
unsigned int frame_size = frame_width * frame_height;
|
int height = 0;
|
||||||
unsigned int errors_sum, r_errors_sum;
|
int i, y, x;
|
||||||
|
gboolean reverse = FALSE;
|
||||||
|
struct aes_stripe *aes_stripe;
|
||||||
|
|
||||||
BUG_ON(stripes_len == 0);
|
BUG_ON(stripes_len == 0);
|
||||||
|
BUG_ON(img_width < frame_width);
|
||||||
|
|
||||||
/* create buffer big enough for max image */
|
/* Calculate height */
|
||||||
img = fpi_img_new(stripes_len * frame_size);
|
i = 0;
|
||||||
|
stripe = stripes;
|
||||||
|
|
||||||
img->flags = FP_IMG_COLORS_INVERTED;
|
/* No offset for 1st image */
|
||||||
img->height = assemble(stripes, stripes_len,
|
aes_stripe = stripe->data;
|
||||||
frame_width, frame_height,
|
aes_stripe->delta_x = 0;
|
||||||
img->data, FALSE, &errors_sum);
|
aes_stripe->delta_y = 0;
|
||||||
img->height = assemble(stripes, stripes_len,
|
do {
|
||||||
frame_width, frame_height,
|
aes_stripe = stripe->data;
|
||||||
img->data, TRUE, &r_errors_sum);
|
|
||||||
|
|
||||||
if (r_errors_sum > errors_sum) {
|
height += aes_stripe->delta_y;
|
||||||
img->height = assemble(stripes, stripes_len,
|
i++;
|
||||||
frame_width, frame_height,
|
stripe = g_slist_next(stripe);
|
||||||
img->data, FALSE, &errors_sum);
|
} while (i < stripes_len);
|
||||||
img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
|
||||||
fp_dbg("normal scan direction");
|
fp_dbg("height is %d", height);
|
||||||
} else {
|
|
||||||
fp_dbg("reversed scan direction");
|
if (height < 0) {
|
||||||
|
reverse = TRUE;
|
||||||
|
height = -height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now that overlap has been removed, resize output image buffer */
|
/* For last frame */
|
||||||
final_size = img->height * frame_width;
|
height += frame_height;
|
||||||
img = fpi_img_resize(img, final_size);
|
|
||||||
img->width = frame_width;
|
/* Create buffer big enough for max image */
|
||||||
|
img = fpi_img_new(img_width * height);
|
||||||
|
img->flags = FP_IMG_COLORS_INVERTED;
|
||||||
|
img->width = img_width;
|
||||||
|
img->height = height;
|
||||||
|
|
||||||
|
/* Assemble stripes */
|
||||||
|
i = 0;
|
||||||
|
stripe = stripes;
|
||||||
|
y = reverse ? (height - frame_height) : 0;
|
||||||
|
x = (img_width - frame_width) / 2;
|
||||||
|
|
||||||
|
do {
|
||||||
|
aes_stripe = stripe->data;
|
||||||
|
|
||||||
|
y += aes_stripe->delta_y;
|
||||||
|
x += aes_stripe->delta_x;
|
||||||
|
|
||||||
|
aes_blit_stripe(img, aes_stripe, x, y, frame_width, frame_height);
|
||||||
|
|
||||||
|
stripe = g_slist_next(stripe);
|
||||||
|
i++;
|
||||||
|
} while (i < stripes_len);
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,24 @@ struct aes_regwrite {
|
||||||
unsigned char value;
|
unsigned char value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct aes_stripe {
|
||||||
|
int delta_x;
|
||||||
|
int delta_y;
|
||||||
|
unsigned char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
|
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||||
unsigned int num_regs, aes_write_regv_cb callback, void *user_data);
|
unsigned int num_regs, aes_write_regv_cb callback, void *user_data);
|
||||||
|
|
||||||
void aes_assemble_image(unsigned char *input, size_t width, size_t height,
|
unsigned int aes_calc_delta(GSList *stripes, size_t stripes_len,
|
||||||
unsigned char *output);
|
unsigned int frame_width, unsigned int frame_height,
|
||||||
|
gboolean reverse);
|
||||||
|
|
||||||
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
|
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
|
||||||
unsigned int frame_width, unsigned int frame_height);
|
unsigned int frame_width, unsigned int frame_height, unsigned int img_width);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -609,13 +609,24 @@ 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;
|
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));
|
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);
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
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,
|
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);
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
|
@ -829,13 +840,9 @@ struct fp_img_driver aes1610_driver = {
|
||||||
},
|
},
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = 128,
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
|
||||||
/* temporarily lowered until we sort out image processing code
|
.bz3_threshold = 50,
|
||||||
* 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,
|
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.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));
|
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||||
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
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[0] = aes1660_init_1;
|
||||||
aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1);
|
aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1);
|
||||||
aesdev->init_seqs[1] = aes1660_init_2;
|
aesdev->init_seqs[1] = aes1660_init_2;
|
||||||
|
@ -102,7 +101,8 @@ struct fp_img_driver aes1660_driver = {
|
||||||
},
|
},
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = FRAME_WIDTH * SCALE_FACTOR,
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
.bz3_threshold = 70,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.close = dev_deinit,
|
||||||
|
|
|
@ -481,10 +481,21 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||||
aesdev->no_finger_cnt++;
|
aesdev->no_finger_cnt++;
|
||||||
if (aesdev->no_finger_cnt == 3) {
|
if (aesdev->no_finger_cnt == 3) {
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
|
unsigned int height, rev_height;
|
||||||
|
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
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,
|
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);
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
|
@ -498,10 +509,13 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||||
} else {
|
} else {
|
||||||
/* obtain next strip */
|
/* obtain next strip */
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* 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);
|
memcpy(stripdata, data + 1, 192*8);
|
||||||
aesdev->no_finger_cnt = 0;
|
aesdev->no_finger_cnt = 0;
|
||||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata);
|
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||||
aesdev->strips_len++;
|
aesdev->strips_len++;
|
||||||
|
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
||||||
|
@ -867,7 +881,7 @@ struct fp_img_driver aes2501_driver = {
|
||||||
},
|
},
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = 192,
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.close = dev_deinit,
|
||||||
|
|
|
@ -204,6 +204,7 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = ssm->priv;
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = dev->priv;
|
||||||
|
struct aes_stripe *stripe;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (data[0] != AES2550_EDATA_MAGIC) {
|
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)) {
|
if (len != (AES2550_STRIP_SIZE - 3)) {
|
||||||
fp_dbg("Bogus frame len: %.4x\n", len);
|
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);
|
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++;
|
aesdev->strips_len++;
|
||||||
|
|
||||||
|
fp_dbg("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,12 +248,13 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
||||||
struct aes2550_dev *aesdev = dev->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) &&
|
||||||
|
aesdev->strips_len) {
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
|
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
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);
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
|
@ -637,7 +644,7 @@ struct fp_img_driver aes2550_driver = {
|
||||||
},
|
},
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = 192,
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.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));
|
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||||
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||||
/* No scaling for AES2660 */
|
/* No scaling for AES2660 */
|
||||||
aesdev->h_scale_factor = 1;
|
|
||||||
aesdev->init_seqs[0] = aes2660_init_1;
|
aesdev->init_seqs[0] = aes2660_init_1;
|
||||||
aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1);
|
aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1);
|
||||||
aesdev->init_seqs[1] = aes2660_init_2;
|
aesdev->init_seqs[1] = aes2660_init_2;
|
||||||
|
@ -103,7 +102,7 @@ struct fp_img_driver aes2660_driver = {
|
||||||
},
|
},
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = FRAME_WIDTH,
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.close = dev_deinit,
|
||||||
|
|
|
@ -52,6 +52,20 @@
|
||||||
|
|
||||||
static void do_capture(struct fp_img_dev *dev);
|
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)
|
static void img_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
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++) {
|
for (i = 0; i < aesdev->frame_number; i++) {
|
||||||
fp_dbg("frame header byte %02x", *ptr);
|
fp_dbg("frame header byte %02x", *ptr);
|
||||||
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;
|
ptr += aesdev->frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -273,19 +273,25 @@ enum capture_states {
|
||||||
/* Returns number of processed bytes */
|
/* Returns number of processed bytes */
|
||||||
static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
|
static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||||
{
|
{
|
||||||
|
struct aes_stripe *stripe;
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = ssm->priv;
|
||||||
struct aesX660_dev *aesdev = dev->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],
|
fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET],
|
||||||
data[AESX660_LAST_FRAME_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) {
|
if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) {
|
||||||
memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->frame_width * FRAME_HEIGHT / 2);
|
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++;
|
aesdev->strips_len++;
|
||||||
return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT);
|
return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT);
|
||||||
} else {
|
} else {
|
||||||
|
@ -302,22 +308,15 @@ static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
struct fp_img *img, *tmp;
|
struct fp_img *img;
|
||||||
|
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
tmp = aes_assemble(aesdev->strips, aesdev->strips_len,
|
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
||||||
aesdev->frame_width, FRAME_HEIGHT);
|
aesdev->frame_width, FRAME_HEIGHT, aesdev->frame_width + aesdev->frame_width / 2);
|
||||||
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
|
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
|
||||||
g_slist_free(aesdev->strips);
|
g_slist_free(aesdev->strips);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
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_image_captured(dev, img);
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
#define AESX660_LAST_FRAME_OFFSET 0x04
|
#define AESX660_LAST_FRAME_OFFSET 0x04
|
||||||
#define AESX660_LAST_FRAME_BIT 0x01
|
#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_IMAGE_OFFSET 43
|
||||||
#define AESX660_BULK_TRANSFER_SIZE 4096
|
#define AESX660_BULK_TRANSFER_SIZE 4096
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue