Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 82 additions & 11 deletions libfprint/drivers/elanspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1329,11 +1329,52 @@ elanspi_fp_assembling_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_fra
return frame->data[y * ctx->frame_width + x];
}

/* Separable gaussian smoothing pass (sigma ~1.2, radius 3). Suppresses
* sensor-noise speckle that otherwise produces spurious, non-repeatable
* image features on the eFSA80SC. */
static void
elanspi_smooth_image (FpImage *img)
{
/* gaussian kernel, sigma=1.2 */
static const guint kern[7] = { 34, 111, 218, 298, 218, 111, 34 };
guint w = img->width, h = img->height;
g_autofree guint8 *tmp = g_malloc (w * h);
guint8 *data = (guint8 *) img->data;

for (guint y = 0; y < h; y++)
for (guint x = 0; x < w; x++)
{
guint acc = 0, wsum = 0;
for (gint k = -3; k <= 3; k++)
{
gint xx = (gint) x + k;
if (xx < 0 || xx >= (gint) w)
continue;
acc += kern[k + 3] * data[y * w + xx];
wsum += kern[k + 3];
}
tmp[y * w + x] = acc / wsum;
}
for (guint y = 0; y < h; y++)
for (guint x = 0; x < w; x++)
{
guint acc = 0, wsum = 0;
for (gint k = -3; k <= 3; k++)
{
gint yy = (gint) y + k;
if (yy < 0 || yy >= (gint) h)
continue;
acc += kern[k + 3] * tmp[yy * w + x];
wsum += kern[k + 3];
}
data[y * w + x] = acc / wsum;
}
}

static void
elanspi_fp_frame_stitch_and_submit (FpiDeviceElanSpi *self)
{
g_autoptr(FpImage) img = NULL;
g_autoptr(FpImage) scaled = NULL;
struct fpi_frame_asmbl_ctx assembling_ctx = {
.image_width = (self->frame_width * 3) / 2,

Expand All @@ -1348,12 +1389,19 @@ elanspi_fp_frame_stitch_and_submit (FpiDeviceElanSpi *self)

fpi_do_movement_estimation (&assembling_ctx, frame_start);
img = fpi_assemble_frames (&assembling_ctx, frame_start);
scaled = fpi_image_resize (img, 2, 2);

scaled->flags |= FPI_IMAGE_PARTIAL | FPI_IMAGE_COLORS_INVERTED;
/* The assembled image is used at native scale: its ~10px ridge period is
* already in the matcher's expected band, and a 2x upscale only starves
* feature extraction. FPI_IMAGE_PARTIAL is not set since on these narrow
* strips it would cull most minutiae as perimeter points. Light smoothing
* suppresses sensor noise that otherwise creates spurious features. */
elanspi_smooth_image (img);
img->flags |= FPI_IMAGE_COLORS_INVERTED;

fp_dbg ("stitched image %dx%d submitted to SIGFM", img->width, img->height);

/* submit image */
fpi_image_device_image_captured (FP_IMAGE_DEVICE (self), g_steal_pointer (&scaled));
fpi_image_device_image_captured (FP_IMAGE_DEVICE (self), g_steal_pointer (&img));

/* clean out frame data */
g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
Expand Down Expand Up @@ -1396,7 +1444,7 @@ elanspi_fp_frame_handler (FpiSsm *ssm, FpiDeviceElanSpi *self)
case ELANSPI_GUESS_EMPTY:
self->fp_empty_counter += 1;
fp_dbg ("<fp_frame> got empty");
if (self->fp_empty_counter > 1)
if (self->fp_empty_counter > 3)
{
fp_dbg ("<fp_frame> have enough debounce");
if (g_slist_length (self->fp_frame_list) >= ELANSPI_MIN_FRAMES_SWIPE)
Expand All @@ -1416,10 +1464,10 @@ elanspi_fp_frame_handler (FpiSsm *ssm, FpiDeviceElanSpi *self)
case ELANSPI_GUESS_FINGERPRINT:
if (self->fp_empty_counter && self->fp_frame_list)
{
if (self->fp_empty_counter < 1)
if (self->fp_empty_counter <= 2)
{
fp_dbg ("<fp_frame> possible bounced fp");
break;
fp_dbg ("<fp_frame> momentary gap during swipe, keeping list");
self->fp_empty_counter = 0;
}
else
{
Expand All @@ -1445,7 +1493,19 @@ elanspi_fp_frame_handler (FpiSsm *ssm, FpiDeviceElanSpi *self)
{
gint difference = elanspi_get_frame_diff_stddev_sq (self, self->last_image, self->prev_frame_image);
fp_dbg ("<fp_frame> diff = %d", difference);
if (difference < ELANSPI_MIN_FRAME_TO_FRAME_DIFF)
gboolean is_enroll =
fpi_device_get_current_action (FP_DEVICE (self)) ==
FPI_DEVICE_ACTION_ENROLL;
gint min_frame_diff =
is_enroll
? ELANSPI_MIN_FRAME_TO_FRAME_DIFF_ENROLL
: ELANSPI_MIN_FRAME_TO_FRAME_DIFF_VERIFY;

fp_dbg ("<fp_frame> threshold = %d, profile = %s",
min_frame_diff,
is_enroll ? "enroll" : "verify");

if (difference < min_frame_diff)
{
fp_dbg ("<fp_frame> ignoring b.c. difference is too small");
break;
Expand Down Expand Up @@ -1641,7 +1701,12 @@ elanspi_fp_capture_finish (FpiSsm *ssm, FpDevice *dev, GError *error)

/* if there was an error, report it */
if (error)
fpi_image_device_session_error (idev, error);
{
if (fpi_device_get_current_action (dev) != FPI_DEVICE_ACTION_NONE)
fpi_image_device_session_error (idev, error);
else
g_error_free (error);
}
}

static void
Expand Down Expand Up @@ -1701,7 +1766,13 @@ fpi_device_elanspi_class_init (FpiDeviceElanSpiClass *klass)
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
dev_class->nr_enroll_stages = 7; /* these sensors are very hit or miss, may as well record a few extras */

img_class->bz3_threshold = 24;
/* SIGFM (SIFT-based) matching: NBIS/bozorth3 cannot discriminate fingers
* on the narrow stitched strips these sensors produce (measured genuine
* and impostor score distributions fully overlap). SIGFM separates them
* by ~3 orders of magnitude. Threshold chosen from a measured corpus:
* impostor pairs scored <= 26, genuine pairs typically 10^3..10^7. */
img_class->algorithm = FPI_DEVICE_ALGO_SIGFM;
img_class->bz3_threshold = 30;
img_class->img_open = elanspi_open;
img_class->activate = elanspi_activate;
img_class->deactivate = elanspi_deactivate;
Expand Down
13 changes: 8 additions & 5 deletions libfprint/drivers/elanspi.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ static const struct elanspi_regtable elanspi_calibration_table_new_page1 = {

// using checkargs ACPI:HIDPID
static const FpIdEntry elanspi_id_table[] = {
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3128}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x322d}, .driver_data = ELANSPI_90LEFT_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3057}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3087}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30c6}, .driver_data = ELANSPI_180_ROTATE},
Expand All @@ -362,17 +364,18 @@ static const FpIdEntry elanspi_id_table[] = {
#define ELANSPI_MIN_EMPTY_INVALID_PERCENT 6
#define ELANSPI_MAX_REAL_INVALID_PERCENT 3

#define ELANSPI_MIN_REAL_STDDEV (592 * 592)
#define ELANSPI_MAX_EMPTY_STDDEV (350 * 350)
#define ELANSPI_MIN_REAL_STDDEV (250 * 250)
#define ELANSPI_MAX_EMPTY_STDDEV (180 * 180)

#define ELANSPI_MIN_FRAMES_DEBOUNCE 2

#define ELANSPI_SWIPE_FRAMES_DISCARD 1
#define ELANSPI_MIN_FRAMES_SWIPE (7 + ELANSPI_SWIPE_FRAMES_DISCARD)
#define ELANSPI_MAX_FRAMES_SWIPE (20 + ELANSPI_SWIPE_FRAMES_DISCARD)
#define ELANSPI_MIN_FRAMES_SWIPE (2 + ELANSPI_SWIPE_FRAMES_DISCARD)
#define ELANSPI_MAX_FRAMES_SWIPE (12 + ELANSPI_SWIPE_FRAMES_DISCARD)

#define ELANSPI_MAX_FRAME_HEIGHT 43
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF (250 * 250)
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF_VERIFY (100 * 100)
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF_ENROLL (100 * 100)

#define ELANSPI_HV_SENSOR_FRAME_DELAY 23

Expand Down
2 changes: 1 addition & 1 deletion libfprint/fp-image.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ fp_image_sigfm_extract_thread_func (GTask * task, void * src_obj,
g_timer_stop (timer);
fp_dbg ("sigfm extract completed in %f secs", g_timer_elapsed (timer, NULL));
g_timer_destroy (timer);
if (sigfm_keypoints_count (data->sigfm_info) < 25)
if (sigfm_keypoints_count (data->sigfm_info) < 5)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
"No enough keypoints found");
Expand Down
3 changes: 2 additions & 1 deletion libfprint/fpi-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ fpi_print_sigfm_match (FpPrint * template, FpPrint * print,
"error in sigfm_match_score");
return FPI_MATCH_ERROR;
}
fp_dbg ("sigfm score %d/%d", score, bz3_threshold);
fp_dbg ("sigfm template %d/%d score %d/%d",
i + 1, template->prints->len, score, bz3_threshold);
if (score >= bz3_threshold)
return FPI_MATCH_SUCCESS;
}
Expand Down