/** \ingroup img * Frees an image. Must be called when you are finished working with an image. * \param img the image to destroy. If NULL, function simply returns. */ API_EXPORTED void fp_img_free(struct fp_img *img) { if (!img) return; if (img->minutiae) free_minutiae(img->minutiae); if (img->binarized) free(img->binarized); g_free(img); }
/************************************************************************* #cat: lfs_detect_minutiae - Takes a grayscale fingerprint image (of arbitrary #cat: size), and returns a map of directional ridge flow in the image #cat: (2 versions), a binarized image designating ridges from valleys, #cat: and a list of minutiae (including position, type, direction, #cat: neighbors, and ridge counts to neighbors). Input: idata - input 8-bit grayscale fingerprint image data iw - width (in pixels) of the image ih - height (in pixels) of the image lfsparms - parameters and thresholds for controlling LFS Output: ominutiae - resulting list of minutiae oimap - resulting IMAP {invalid (-1) or valid ridge directions} onmap - resulting NMAP {invalid (-1), high-curvature (-2), blanked blocks {-3} or valid ridge directions} omw - width (in blocks) of image maps omh - height (in blocks) of image maps obdata - resulting binarized image {0 = black pixel (ridge) and 255 = white pixel (valley)} obw - width (in pixels) of the binary image obh - height (in pixels) of the binary image Return Code: Zero - successful completion Negative - system error **************************************************************************/ int lfs_detect_minutiae(MINUTIAE **ominutiae, int **oimap, int **onmap, int *omw, int *omh, unsigned char **obdata, int *obw, int *obh, unsigned char *idata, const int iw, const int ih, const LFSPARMS *lfsparms) { unsigned char *pdata, *bdata; int pw, ph, bw, bh; DIR2RAD *dir2rad; DFTWAVES *dftwaves; ROTGRIDS *dftgrids; ROTGRIDS *dirbingrids; int *imap, *nmap, mw, mh; int ret, maxpad; MINUTIAE *minutiae; set_timer(total_timer); /******************/ /* INITIALIZATION */ /******************/ /* If LOG_REPORT defined, open log report file. */ if((ret = open_logfile())) /* If system error, exit with error code. */ return(ret); /* Determine the maximum amount of image padding required to support */ /* LFS processes. */ maxpad = get_max_padding(lfsparms->blocksize, lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h, lfsparms->isobin_grid_dim); /* Initialize lookup table for converting integer IMAP directions */ /* to angles in radians. */ if((ret = init_dir2rad(&dir2rad, lfsparms->num_directions))){ /* Free memory allocated to this point. */ return(ret); } /* Initialize wave form lookup tables for DFT analyses. */ /* used for direction binarization. */ if((ret = init_dftwaves(&dftwaves, dft_coefs, lfsparms->num_dft_waves, lfsparms->blocksize))){ /* Free memory allocated to this point. */ free_dir2rad(dir2rad); return(ret); } /* Initialize lookup table for pixel offsets to rotated grids */ /* used for DFT analyses. */ if((ret = init_rotgrids(&dftgrids, iw, ih, maxpad, lfsparms->start_dir_angle, lfsparms->num_directions, lfsparms->blocksize, lfsparms->blocksize, RELATIVE2ORIGIN))){ /* Free memory allocated to this point. */ free_dir2rad(dir2rad); free_dftwaves(dftwaves); return(ret); } /* Pad input image based on max padding. */ if(maxpad > 0){ /* May not need to pad at all */ if((ret = pad_uchar_image(&pdata, &pw, &ph, idata, iw, ih, maxpad, lfsparms->pad_value))){ /* Free memory allocated to this point. */ free_dir2rad(dir2rad); free_dftwaves(dftwaves); free_rotgrids(dftgrids); return(ret); } } else{ /* If padding is unnecessary, then copy the input image. */ pdata = (unsigned char *)malloc(iw*ih); if(pdata == (unsigned char *)NULL){ /* Free memory allocated to this point. */ free_dir2rad(dir2rad); free_dftwaves(dftwaves); free_rotgrids(dftgrids); fprintf(stderr, "ERROR : lfs_detect_minutiae : malloc : pdata\n"); return(-430); } memcpy(pdata, idata, iw*ih); pw = iw; ph = ih; } /* Scale input image to 6 bits [0..63] */ /* !!! Would like to remove this dependency eventualy !!! */ /* But, the DFT computations will need to be changed, and */ /* could not get this work upon first attempt. */ bits_8to6(pdata, pw, ph); print2log("\nINITIALIZATION AND PADDING DONE\n"); /******************/ /* IMAP */ /******************/ set_timer(imap_timer); /* Generate IMAP for the input image. */ if((ret = gen_imap(&imap, &mw, &mh, pdata, pw, ph, dir2rad, dftwaves, dftgrids, lfsparms))){ /* Free memory allocated to this point. */ free_dir2rad(dir2rad); free_dftwaves(dftwaves); free_rotgrids(dftgrids); free(pdata); return(ret); } free_dir2rad(dir2rad); free_dftwaves(dftwaves); free_rotgrids(dftgrids); print2log("\nIMAP DONE\n"); /* Generate NMAP from the IMAP of the input image. */ if((ret = gen_nmap(&nmap, imap, mw, mh, lfsparms))){ /* Free memory allocated to this point. */ free(pdata); free(imap); return(ret); } print2log("\nNMAP DONE\n"); time_accum(imap_timer, imap_time); /******************/ /* BINARIZARION */ /******************/ set_timer(bin_timer); /* Initialize lookup table for pixel offsets to rotated grids */ /* used for directional binarization. */ if((ret = init_rotgrids(&dirbingrids, iw, ih, maxpad, lfsparms->start_dir_angle, lfsparms->num_directions, lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h, RELATIVE2CENTER))){ /* Free memory allocated to this point. */ free(pdata); free(imap); free(nmap); return(ret); } /* Binarize input image based on NMAP information. */ if((ret = binarize(&bdata, &bw, &bh, pdata, pw, ph, nmap, mw, mh, dirbingrids, lfsparms))){ /* Free memory allocated to this point. */ free(pdata); free(imap); free(nmap); free_rotgrids(dirbingrids); return(ret); } free_rotgrids(dirbingrids); /* Check dimension of binary image. If they are different from */ /* the input image, then ERROR. */ if((iw != bw) || (ih != bh)){ /* Free memory allocated to this point. */ free(pdata); free(imap); free(nmap); free(bdata); fprintf(stderr, "ERROR : lfs_detect_minutiae : binary image has bad dimensions : %d, %d\n", bw, bh); return(-431); } print2log("\nBINARIZATION DONE\n"); time_accum(bin_timer, bin_time); /******************/ /* DETECTION */ /******************/ set_timer(minutia_timer); /* Convert 8-bit grayscale binary image [0,255] to */ /* 8-bit binary image [0,1]. */ gray2bin(1, 1, 0, bdata, iw, ih); /* Allocate list of maximum number of minutia pointers. */ if((ret = alloc_minutiae(&minutiae, MAX_MINUTIAE))){ return(ret); } /* Detect the minutiae in the binarized image. */ if((ret = detect_minutiae(minutiae, bdata, iw, ih, imap, nmap, mw, mh, lfsparms))){ /* Free memory allocated to this point. */ free(pdata); free(imap); free(nmap); free(bdata); return(ret); } time_accum(minutia_timer, minutia_time); set_timer(rm_minutia_timer); if((ret = remove_false_minutia(minutiae, bdata, iw, ih, nmap, mw, mh, lfsparms))){ /* Free memory allocated to this point. */ free(pdata); free(imap); free(nmap); free(bdata); free_minutiae(minutiae); return(ret); } print2log("\nMINUTIA DETECTION DONE\n"); time_accum(rm_minutia_timer, rm_minutia_time); /******************/ /* RIDGE COUNTS */ /******************/ set_timer(ridge_count_timer); if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){ /* Free memory allocated to this point. */ free(pdata); free(imap); free(nmap); free(bdata); free_minutiae(minutiae); return(ret); } print2log("\nNEIGHBOR RIDGE COUNT DONE\n"); time_accum(ridge_count_timer, ridge_count_time); /******************/ /* WRAP-UP */ /******************/ /* Convert 8-bit binary image [0,1] to 8-bit */ /* grayscale binary image [0,255]. */ gray2bin(1, 255, 0, bdata, iw, ih); /* Deallocate working memory. */ free(pdata); /* Assign results to output pointers. */ *oimap = imap; *onmap = nmap; *omw = mw; *omh = mh; *obdata = bdata; *obw = bw; *obh = bh; *ominutiae = minutiae; time_accum(total_timer, total_time); /******************/ /* PRINT TIMINGS */ /******************/ /* These Timings will print when TIMER is defined. */ /* print IMAP generation timing statistics */ print_time(stderr, "TIMER: IMAP time = %f (secs)\n", imap_time); /* print binarization timing statistics */ print_time(stderr, "TIMER: Binarization time = %f (secs)\n", bin_time); /* print minutia detection timing statistics */ print_time(stderr, "TIMER: Minutia Detection time = %f (secs)\n", minutia_time); /* print minutia removal timing statistics */ print_time(stderr, "TIMER: Minutia Removal time = %f (secs)\n", rm_minutia_time); /* print neighbor ridge count timing statistics */ print_time(stderr, "TIMER: Neighbor Ridge Counting time = %f (secs)\n", ridge_count_time); /* print total timing statistics */ print_time(stderr, "TIMER: Total time = %f (secs)\n", total_time); /* If LOG_REPORT defined, close log report file. */ if((ret = close_logfile())) return(ret); return(0); }