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:
Daniel Drake 2007-11-08 17:04:45 +00:00
parent a73cbc10fb
commit e3451158e9
5 changed files with 68 additions and 3 deletions

View file

@ -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)])],

View file

@ -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 \

View file

@ -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,

View file

@ -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);

View file

@ -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;