Custom image resizing
mindtct appears to completely ignore the pixels-per-mm input parameter (ippmm). When processing AES4000 images, the binarized image is completely mangled and a lot of ridge information is lost. Resizing the AES4000's small images results in a huge imaging performance gain. We use imagemagick for the resizing, as it's resizing code resamples the image too (smoothing it out), which further improves performance.
This commit is contained in:
parent
a73cbc10fb
commit
e3451158e9
5 changed files with 68 additions and 3 deletions
|
@ -25,6 +25,10 @@ PKG_CHECK_MODULES(GLIB, "glib-2.0")
|
||||||
AC_SUBST(GLIB_CFLAGS)
|
AC_SUBST(GLIB_CFLAGS)
|
||||||
AC_SUBST(GLIB_LIBS)
|
AC_SUBST(GLIB_LIBS)
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(IMAGEMAGICK, "ImageMagick")
|
||||||
|
AC_SUBST(IMAGEMAGICK_CFLAGS)
|
||||||
|
AC_SUBST(IMAGEMAGICK_LIBS)
|
||||||
|
|
||||||
# Examples build
|
# Examples build
|
||||||
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
|
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
|
||||||
[build example applications (default n)])],
|
[build example applications (default n)])],
|
||||||
|
|
|
@ -43,9 +43,9 @@ NBIS_SRC = \
|
||||||
nbis/mindtct/sort.c \
|
nbis/mindtct/sort.c \
|
||||||
nbis/mindtct/util.c
|
nbis/mindtct/util.c
|
||||||
|
|
||||||
libfprint_la_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(AM_CFLAGS)
|
libfprint_la_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(IMAGEMAGICK_CFLAGS) $(AM_CFLAGS)
|
||||||
libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
|
libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
|
||||||
libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS)
|
libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS) $(IMAGEMAGICK_LIBS)
|
||||||
|
|
||||||
libfprint_la_SOURCES = \
|
libfprint_la_SOURCES = \
|
||||||
fp_internal.h \
|
fp_internal.h \
|
||||||
|
|
|
@ -218,6 +218,7 @@ struct fp_img_driver aes4000_driver = {
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = 96,
|
.img_height = 96,
|
||||||
.img_width = 96,
|
.img_width = 96,
|
||||||
|
.enlarge_factor = 3,
|
||||||
|
|
||||||
.init = dev_init,
|
.init = dev_init,
|
||||||
.exit = dev_exit,
|
.exit = dev_exit,
|
||||||
|
|
|
@ -126,6 +126,7 @@ struct fp_img_driver {
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
int img_width;
|
int img_width;
|
||||||
int img_height;
|
int img_height;
|
||||||
|
unsigned int enlarge_factor;
|
||||||
|
|
||||||
/* Device operations */
|
/* Device operations */
|
||||||
int (*init)(struct fp_img_dev *dev, unsigned long driver_data);
|
int (*init)(struct fp_img_dev *dev, unsigned long driver_data);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <magick/ImageMagick.h>
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fp_internal.h"
|
||||||
#include "nbis/include/bozorth.h"
|
#include "nbis/include/bozorth.h"
|
||||||
|
@ -226,6 +227,50 @@ API_EXPORTED void fp_img_standardize(struct fp_img *img)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct fp_img *im_resize(struct fp_img *img, unsigned int factor)
|
||||||
|
{
|
||||||
|
Image *mimg;
|
||||||
|
Image *resized;
|
||||||
|
ExceptionInfo *exception;
|
||||||
|
MagickBooleanType ret;
|
||||||
|
int new_width = img->width * factor;
|
||||||
|
int new_height = img->height * factor;
|
||||||
|
struct fp_img *newimg;
|
||||||
|
|
||||||
|
/* It is possible to implement resizing using a simple algorithm, however
|
||||||
|
* we use ImageMagick because it applies some kind of smoothing to the
|
||||||
|
* result, which improves matching performances in my experiments. */
|
||||||
|
|
||||||
|
if (!IsMagickInstantiated())
|
||||||
|
MagickCoreGenesis(NULL, MagickFalse);
|
||||||
|
|
||||||
|
exception = AcquireExceptionInfo();
|
||||||
|
|
||||||
|
mimg = ConstituteImage(img->width, img->height, "I", CharPixel, img->data, exception);
|
||||||
|
|
||||||
|
ClearMagickException(exception);
|
||||||
|
resized = ResizeImage(mimg, new_width, new_height, 0, 1.0, exception);
|
||||||
|
|
||||||
|
newimg = fpi_img_new(new_width * new_height);
|
||||||
|
newimg->width = new_width;
|
||||||
|
newimg->height = new_height;
|
||||||
|
newimg->flags = img->flags;
|
||||||
|
|
||||||
|
ClearMagickException(exception);
|
||||||
|
ret = ExportImagePixels(resized, 0, 0, new_width, new_height, "I",
|
||||||
|
CharPixel, newimg->data, exception);
|
||||||
|
if (ret != MagickTrue) {
|
||||||
|
fp_err("export failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyImage(mimg);
|
||||||
|
DestroyImage(resized);
|
||||||
|
DestroyExceptionInfo(exception);
|
||||||
|
|
||||||
|
return newimg;
|
||||||
|
}
|
||||||
|
|
||||||
/* Based on write_minutiae_XYTQ and bz_load */
|
/* Based on write_minutiae_XYTQ and bz_load */
|
||||||
static void minutiae_to_xyt(MINUTIAE *minutiae, int bwidth,
|
static void minutiae_to_xyt(MINUTIAE *minutiae, int bwidth,
|
||||||
int bheight, unsigned char *buf)
|
int bheight, unsigned char *buf)
|
||||||
|
@ -261,7 +306,7 @@ static void minutiae_to_xyt(MINUTIAE *minutiae, int bwidth,
|
||||||
xyt->nrows = nmin;
|
xyt->nrows = nmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fpi_img_detect_minutiae(struct fp_img_dev *imgdev, struct fp_img *img,
|
int fpi_img_detect_minutiae(struct fp_img_dev *imgdev, struct fp_img *_img,
|
||||||
struct fp_print_data **ret)
|
struct fp_print_data **ret)
|
||||||
{
|
{
|
||||||
MINUTIAE *minutiae;
|
MINUTIAE *minutiae;
|
||||||
|
@ -272,8 +317,20 @@ int fpi_img_detect_minutiae(struct fp_img_dev *imgdev, struct fp_img *img,
|
||||||
unsigned char *bdata;
|
unsigned char *bdata;
|
||||||
int bw, bh, bd;
|
int bw, bh, bd;
|
||||||
struct fp_print_data *print;
|
struct fp_print_data *print;
|
||||||
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
|
||||||
|
struct fp_img *img = _img;
|
||||||
|
int free_img = 0;
|
||||||
GTimer *timer;
|
GTimer *timer;
|
||||||
|
|
||||||
|
if (imgdrv->enlarge_factor) {
|
||||||
|
/* FIXME: enlarge_factor should not exist! instead, MINDTCT should
|
||||||
|
* actually look at the value of the pixels-per-mm parameter and
|
||||||
|
* figure out itself when the image needs to be treated as if it
|
||||||
|
* were bigger. */
|
||||||
|
img = im_resize(_img, imgdrv->enlarge_factor);
|
||||||
|
free_img = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* 25.4 mm per inch */
|
/* 25.4 mm per inch */
|
||||||
timer = g_timer_new();
|
timer = g_timer_new();
|
||||||
r = get_minutiae(&minutiae, &quality_map, &direction_map,
|
r = get_minutiae(&minutiae, &quality_map, &direction_map,
|
||||||
|
@ -284,6 +341,8 @@ int fpi_img_detect_minutiae(struct fp_img_dev *imgdev, struct fp_img *img,
|
||||||
g_timer_stop(timer);
|
g_timer_stop(timer);
|
||||||
fp_dbg("minutiae scan completed in %f secs", g_timer_elapsed(timer, NULL));
|
fp_dbg("minutiae scan completed in %f secs", g_timer_elapsed(timer, NULL));
|
||||||
g_timer_destroy(timer);
|
g_timer_destroy(timer);
|
||||||
|
if (free_img)
|
||||||
|
g_free(img);
|
||||||
if (r) {
|
if (r) {
|
||||||
fp_err("get minutiae failed, code %d", r);
|
fp_err("get minutiae failed, code %d", r);
|
||||||
return r;
|
return r;
|
||||||
|
|
Loading…
Reference in a new issue