|
Hi! I've been working on gain support for aes1610. So here's a patch for that. I would really like to have some feedback from other users having this device. I'd like to know if you get better results with it (or not). >From my tests, I get a bit more minutiae (something like 20~25) but the scores I get are still not that much > 10 when it matches... I didn't have any false positive but there are still too many false negatives compared to the windows driver. There will be some work to do on enrollment/matching. It will need some adjustments and tweaking. The code will need some cleaning after that. |
diff -aburNp ./git/libfprint/drivers/aes1610.c ./patched/libfprint/drivers/aes1610.c
--- ./git/libfprint/drivers/aes1610.c 2008-01-05 12:56:15.000000000 +0100
+++ ./patched/libfprint/drivers/aes1610.c 2008-01-05 13:04:09.000000000 +0100
@@ -59,6 +59,8 @@
/* maximum number of frames to read during a scan */
/* FIXME reduce substantially */
#define MAX_FRAMES 350
+#define GAIN_STATUS_FIRST 1
+#define GAIN_STATUS_NORMAL 2
static int read_data(struct fp_img_dev *dev, unsigned char *data, size_t len)
{
@@ -143,119 +145,7 @@ static const struct aes_regwrite finger_
{ 0x1D, 0x00 }
};
-static int detect_finger(struct fp_img_dev *dev)
-{
- unsigned char buffer[19];
- int r;
- int i;
- int sum = 0;
-
- r = aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs));
- if (r < 0)
- return r;
-
- r = read_data(dev, buffer, 19);
- if (r < 0)
- return r;
-
- for (i = 3; i < 17; i++)
- sum += (buffer[i] & 0xf) + (buffer[i] >> 4);
-
- /* We need to answer something if no finger has been detected */
- if (sum <= 20) {
- r = aes_write_regv(dev, finger_det_none, G_N_ELEMENTS(finger_det_none));
- if (r < 0)
- return r;
- }
-
- return sum > 20;
-}
-
-static int await_finger_on(struct fp_img_dev *dev)
-{
- int r;
- do {
- r = detect_finger(dev);
- } while (r == 0);
- return (r < 0) ? r : 0;
-}
-
-/* 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(unsigned char *input, unsigned char *output,
- int num_strips, gboolean reverse, unsigned int *errors_sum)
-{
- uint8_t *assembled = output;
- int frame;
- uint32_t image_height = FRAME_HEIGHT;
- unsigned int min_error;
- *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(input, FRAME_WIDTH, FRAME_HEIGHT, output);
- input += FRAME_WIDTH * (FRAME_HEIGHT / 2);
-
- if (reverse)
- output -= FRAME_SIZE;
- else
- output += FRAME_SIZE;
- }
-
- /* 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 const struct aes_regwrite capture_reqs[] = {
+static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x01 },
{ 0x80, 0x12 },
{ 0x84, 0x01 },
@@ -265,8 +155,8 @@ static const struct aes_regwrite capture
{ 0x8B, 0x0E },
{ 0x8C, 0x90 },
{ 0xBE, 0x23 },
- { 0x29, 0x06 },
- { 0x2A, 0x35 },
+ { 0x29, 0x04 },
+ { 0x2A, 0xFF },
{ 0x96, 0x00 },
{ 0x98, 0x03 },
{ 0x99, 0x00 },
@@ -381,14 +271,277 @@ static const struct aes_regwrite capture
{ 0x81, 0x01 }
};
-static const struct aes_regwrite strip_scan_reqs[] = {
- { 0xBE, 0x23 },
- { 0x29, 0x06 },
- { 0x2A, 0x35 },
- { 0xBD, 0x4F },
+/* Sent to the device every 2/3 strips to adjust the gain */
+static struct aes_regwrite strip_scan_reqs[] = {
+ { 0xBE, 0x23 }, // default value for the gain
+ { 0x29, 0x04 }, // default value for the gain
+ { 0x2A, 0xFF }, // default value for the gain
+ { 0xBD, 0x4F }, // default value for the gain
{ 0xFF, 0x00 }
};
+/*
+ The different possible values for 0xBE register
+*/
+static unsigned char list_BE_values[10] = {
+ 0x23, 0x43, 0x63, 0x64, 0x65, 0x67, 0x6A, 0x6B
+};
+
+/*
+ The different possible values for 0xBD register
+*/
+static unsigned char list_BD_values[10] = {
+ 0x48, 0x4B, 0x4F, 0x52, 0x57, 0x59, 0x5B
+};
+
+/*
+ Adjust the gain according to the histogram data
+ 0xbd, 0xbe, 0x29 and 0x2A registers are affected
+ Returns 0 if no problem occured
+ TODO: This is a basic support for gain. It needs testing/tweaking.
+ */
+static int adjust_gain(unsigned char *buffer, int status)
+{
+ // The position in the array of possible values for 0xBE and 0xBD registers
+ static int pos_list_BE = 0;
+ static int pos_list_BD = 0;
+
+ // This is the first adjustement (we begin acquisition)
+ // We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step
+ if (status == GAIN_STATUS_FIRST) {
+ if (buffer[1] > 0x78) { // maximum gain needed
+ strip_scan_reqs[0].value = 0x6B;
+ strip_scan_reqs[1].value = 0x04;
+ strip_scan_reqs[2].value = 0xFF;
+ strip_scan_reqs[3].value = 0x5B;
+ }
+ else if (buffer[1] > 0x55) {
+ strip_scan_reqs[0].value = 0x63;
+ strip_scan_reqs[1].value = 0x15;
+ strip_scan_reqs[2].value = 0x35;
+ strip_scan_reqs[3].value = 0x4F;
+ }
+ else if (buffer[1] > 0x40 || buffer[16] > 0x19) {
+ strip_scan_reqs[0].value = 0x43;
+ strip_scan_reqs[1].value = 0x13;
+ strip_scan_reqs[2].value = 0x35;
+ strip_scan_reqs[3].value = 0x4B;
+ }
+ else { // minimum gain needed
+ strip_scan_reqs[0].value = 0x23;
+ strip_scan_reqs[1].value = 0x07;
+ strip_scan_reqs[2].value = 0x35;
+ strip_scan_reqs[3].value = 0x48;
+ }
+
+ // Now copy this values in capture_reqs
+ capture_reqs[8].value = strip_scan_reqs[0].value;
+ capture_reqs[9].value = strip_scan_reqs[1].value;
+ capture_reqs[10].value = strip_scan_reqs[2].value;
+ capture_reqs[21].value = strip_scan_reqs[3].value;
+
+ fp_dbg("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
+ }
+
+ // Every 2/3 strips
+ // We try to soften big changes of the gain (at least for 0xBE and 0xBD
+ // FIXME: This softenning will need testing and tweaking too
+ else if (status == GAIN_STATUS_NORMAL) {
+ if (buffer[514] > 0x78) { // maximum gain needed
+ if (pos_list_BE < 7)
+ pos_list_BE++;
+
+ if (pos_list_BD < 6)
+ pos_list_BD++;
+
+ strip_scan_reqs[1].value = 0x04;
+ strip_scan_reqs[2].value = 0xFF;
+ }
+ else if (buffer[514] > 0x55) {
+ if (pos_list_BE < 2)
+ pos_list_BE++;
+ else if (pos_list_BE > 2)
+ pos_list_BE--;
+
+ if (pos_list_BD < 2)
+ pos_list_BD++;
+ else if (pos_list_BD > 2)
+ pos_list_BD--;
+
+ strip_scan_reqs[1].value = 0x15;
+ strip_scan_reqs[2].value = 0x35;
+ }
+ else if (buffer[514] > 0x40 || buffer[529] > 0x19) {
+ if (pos_list_BE < 1)
+ pos_list_BE++;
+ else if (pos_list_BE > 1)
+ pos_list_BE--;
+
+ if (pos_list_BD < 1)
+ pos_list_BD++;
+ else if (pos_list_BD > 1)
+ pos_list_BD--;
+
+ strip_scan_reqs[1].value = 0x13;
+ strip_scan_reqs[2].value = 0x35;
+ }
+ else { // minimum gain needed
+ if (pos_list_BE > 0)
+ pos_list_BE--;
+
+ if (pos_list_BD > 0)
+ pos_list_BD--;
+
+ strip_scan_reqs[1].value = 0x07;
+ strip_scan_reqs[2].value = 0x35;
+ }
+
+ strip_scan_reqs[0].value = list_BE_values[pos_list_BE];
+ strip_scan_reqs[3].value = list_BD_values[pos_list_BD];
+
+ fp_dbg("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
+ }
+
+ // Unknown status
+ else {
+ fp_err("Unexpected gain status.");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ Restore the default gain values
+*/
+static void restore_gain()
+{
+ strip_scan_reqs[0].value = list_BE_values[0];
+ strip_scan_reqs[1].value = 0x04;
+ strip_scan_reqs[2].value = 0xFF;
+ strip_scan_reqs[3].value = list_BD_values[0];
+
+ capture_reqs[8].value = list_BE_values[0];
+ capture_reqs[9].value = 0x04;
+ capture_reqs[10].value = 0xFF;
+ capture_reqs[21].value = list_BD_values[0];
+}
+
+static int detect_finger(struct fp_img_dev *dev)
+{
+ unsigned char buffer[19];
+ int r;
+ int i;
+ int sum = 0;
+
+ r = aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs));
+ if (r < 0)
+ return r;
+
+ r = read_data(dev, buffer, 19);
+ if (r < 0)
+ return r;
+
+ for (i = 3; i < 17; i++)
+ sum += (buffer[i] & 0xf) + (buffer[i] >> 4);
+
+ /* We need to answer something if no finger has been detected */
+ if (sum <= 20) {
+ r = aes_write_regv(dev, finger_det_none, G_N_ELEMENTS(finger_det_none));
+ if (r < 0)
+ return r;
+ }
+
+ if (sum > 20)
+ adjust_gain(buffer,GAIN_STATUS_FIRST);
+
+ return sum > 20;
+}
+
+static int await_finger_on(struct fp_img_dev *dev)
+{
+ int r;
+ do {
+ r = detect_finger(dev);
+ } while (r == 0);
+ return (r < 0) ? r : 0;
+}
+
+/* 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(unsigned char *input, unsigned char *output,
+ int num_strips, gboolean reverse, unsigned int *errors_sum)
+{
+ uint8_t *assembled = output;
+ int frame;
+ uint32_t image_height = FRAME_HEIGHT;
+ unsigned int min_error;
+ *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(input, FRAME_WIDTH, FRAME_HEIGHT, output);
+ input += FRAME_WIDTH * (FRAME_HEIGHT / 2);
+
+ if (reverse)
+ output -= FRAME_SIZE;
+ else
+ output += FRAME_SIZE;
+ }
+
+ /* 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 const struct aes_regwrite capture_stop[] = {
{ 0x81,0x00 }
};
@@ -415,30 +568,20 @@ static int capture(struct fp_img_dev *de
if (r < 0)
return r;
- /* FIXME: use histogram data above for gain calibration (0x8e xx) */
img = fpi_img_new((3 * MAX_FRAMES * FRAME_SIZE) / 2);
imgptr = img->data;
cooked = imgptr + (MAX_FRAMES * FRAME_SIZE) / 2;
- r = read_data(dev, buf, 665);
- if (r < 0)
- goto err;
- memcpy(imgptr, buf + 1, 128*4);
- imgptr += 128*4;
-
- r = read_data(dev, buf, 665);
- if (r < 0)
- goto err;
- memcpy(imgptr, buf + 1, 128*4);
- imgptr += 128*4;
-
- /* we start at 2 because we captured 2 frames above. the above captures
- * should possibly be moved into the loop below, or discarded altogether */
- for (nstrips = 2; nstrips < MAX_FRAMES - 2; nstrips++) {
+ /* we stop at nstrips-2 because we captured 2 frames after the loop. */
+ for (nstrips = 0; nstrips < MAX_FRAMES - 2; nstrips += 2) {
+ /* we don't have to request more frames until we have received the 2 firsts */
+ if (nstrips >= 2) {
r = aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs));
if (r < 0)
goto err;
+ }
+
r = read_data(dev, buf, 665);
if (r < 0)
goto err;
@@ -452,7 +595,7 @@ static int capture(struct fp_img_dev *de
imgptr += 128*4;
sum = 0;
- for (i = 515; i != 530; i++)
+ for (i = 516; i != 530; i++)
{
/* histogram[i] = number of pixels of value i
Only the pixel values from 10 to 15 are used to detect finger. */
@@ -468,11 +611,17 @@ static int capture(struct fp_img_dev *de
else
count_blank = 0;
- /* if we got 50 blank frames, assume scan has ended. */
- if (count_blank >= 50)
+ /* if we got 5 blank frames, assume scan has ended. */
+ if (count_blank >= 5)
break;
+
+ /* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */
+ adjust_gain(buf, GAIN_STATUS_NORMAL);
}
+ // Acquisition finished: restore default gain values
+ restore_gain();
+
r = aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop));
if (r < 0)
goto err;
_______________________________________________ fprint mailing list [email protected] http://lists.reactivated.net/mailman/listinfo/fprint
