void snip_rot_subimage(unsigned char *data, const int w, const int h, unsigned char *idata, const int iw, const int ih, const int cx, const int cy, const float ang, unsigned char pix) { float c, s, fx, fy, sfx, sfy; int ix, iy, x, y; float hw, hh; hw = (float)iw / 2.0; hh = (float)ih / 2.0; c = cos(ang); s = sin(ang); sfx = (cx - (hw * c) - (hh * s)); sfy = (cy + (hw * s) - (hh * c)); for(y = 0; y < ih; y++, sfx += s, sfy += c) { for(x = 0, fx = sfx, fy = sfy; x < iw; x++, fx += c, fy -= s) { ix = sround(fx); iy = sround(fy); *idata++ = ((ix >= 0) && (ix < w) && (iy >= 0) && (iy < h))?data[ix+iy*w]:pix; } } }
/************************************************************************* ************************************************************************** #cat: lfs2nist_minutia_XYT - Converts XYT minutiae attributes in LFS native #cat: representation to NIST internal representation Input: minutia - LFS minutia structure containing attributes to be converted Output: ox - NIST internal based x-pixel coordinate oy - NIST internal based y-pixel coordinate ot - NIST internal based minutia direction/orientation **************************************************************************/ void lfs2nist_minutia_XYT(int *ox, int *oy, int *ot, const MINUTIA *minutia, const int iw, const int ih) { int x, y, t; float degrees_per_unit; /* XYT's according to NIST internal rep: */ /* 1. pixel coordinates with origin bottom-left */ /* 2. orientation in degrees on range [0..360] */ /* with 0 pointing east and increasing counter */ /* clockwise (same as M1) */ /* 3. direction pointing out and away from the */ /* ridge ending or bifurcation valley */ /* (opposite direction from M1) */ x = minutia->x; y = ih - minutia->y; degrees_per_unit = 180 / (float)NUM_DIRECTIONS; t = (270 - sround(minutia->direction * degrees_per_unit)) % 360; if(t < 0){ t += 360; } *ox = x; *oy = y; *ot = t; }
/* Based on write_minutiae_XYTQ and bz_load */ static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth, int bheight, unsigned char *buf) { int i; struct fp_minutia *minutia; struct minutiae_struct c[MAX_FILE_MINUTIAE]; struct xyt_struct *xyt = (struct xyt_struct *) buf; /* FIXME: only considers first 150 minutiae (MAX_FILE_MINUTIAE) */ /* nist does weird stuff with 150 vs 1000 limits */ int nmin = min(minutiae->num, MAX_FILE_MINUTIAE); for (i = 0; i < nmin; i++){ minutia = minutiae->list[i]; lfs2nist_minutia_XYT(&c[i].col[0], &c[i].col[1], &c[i].col[2], minutia, bwidth, bheight); c[i].col[3] = sround(minutia->reliability * 100.0); if (c[i].col[2] > 180) c[i].col[2] -= 360; } qsort((void *) &c, (size_t) nmin, sizeof(struct minutiae_struct), sort_x_y); for (i = 0; i < nmin; i++) { xyt->xcol[i] = c[i].col[0]; xyt->ycol[i] = c[i].col[1]; xyt->thetacol[i] = c[i].col[2]; } xyt->nrows = nmin; }
/************************************************************************* ************************************************************************** #cat: lfs2m1_minutia_XYT - Converts XYT minutiae attributes in LFS native #cat: representation to M1 (ANSI INCITS 378-2004) representation Input: minutia - LFS minutia structure containing attributes to be converted Output: ox - M1 based x-pixel coordinate oy - M1 based y-pixel coordinate ot - M1 based minutia direction/orientation **************************************************************************/ void lfs2m1_minutia_XYT(int *ox, int *oy, int *ot, const MINUTIA *minutia) { int x, y, t; float degrees_per_unit; /* XYT's according to M1 (ANSI INCITS 378-2004): */ /* 1. pixel coordinates with origin top-left */ /* 2. orientation in degrees on range [0..179] */ /* with 0 pointing east and increasing counter */ /* clockwise */ /* 3. direction pointing up the ridge ending or */ /* bifurcaiton valley */ x = minutia->x; y = minutia->y; degrees_per_unit = 180 / (float)NUM_DIRECTIONS; t = (90 - sround(minutia->direction * degrees_per_unit)) % 360; if(t < 0){ t += 360; } /* range of theta is 0..179 because angles are in units of 2 degress */ t = t / 2; *ox = x; *oy = y; *ot = t; }
bool inRange(double in) { if (std::is_integral<T_OUT>::value) { in = sround((double)in); } return std::is_same<double, T_OUT>::value || (in >= static_cast<double>(std::numeric_limits<T_OUT>::lowest()) && in <= static_cast<double>(std::numeric_limits<T_OUT>::max())); }
static void kf_bfly2( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, int m ) { kiss_fft_cpx * Fout2; kiss_fft_cpx * tw1 = st->twiddles; kiss_fft_cpx t(0, 0); Fout2 = Fout + m; do { int32_t Ar, Ai, Br, Bi; Ar = Fout->real(); Ai = Fout->imag(); Br = Fout2->real(); Bi = Fout2->imag(); int32_t Rar, Rai, Rbr, Rbi; Rar = (sround(Ar*16384 + ((int)Br)*((int)tw1->real())/2 - ((int)Bi)*((int)tw1->imag())/2)); Rai = (sround(Ai*16384 + ((int)Br)*((int)tw1->imag())/2 + ((int)Bi)*((int)tw1->real())/2)); Rbr = (sround(Ar*16384 - ((int)Br)*((int)tw1->real())/2 + ((int)Bi)*((int)tw1->imag())/2)); Rbi = (sround(Ai*16384 - ((int)Br)*((int)tw1->imag())/2 - ((int)Bi)*((int)tw1->real())/2)); if((abs(Rar) > 32767) || (abs(Rai) > 32767) || (abs(Rbr) > 32767) || (abs(Rbi) > 32767)) { qDebug()<<"assert\n"; } *Fout = kiss_fft_cpx(Rar, Rai); *Fout2 = kiss_fft_cpx(Rbr, Rbi); tw1 += fstride; ++Fout2; ++Fout; }while (--m); }
/************************************************************************* ************************************************************************** #cat: dirbinarize - Determines the binary value of a grayscale pixel based #cat: on a VALID IMAP ridge flow direction. CAUTION: The image to which the input pixel points must be appropriately padded to account for the radius of the rotated grid. Otherwise, this routine may access "unkown" memory. Input: pptr - pointer to current grayscale pixel idir - IMAP integer direction associated with the block the current is in dirbingrids - set of precomputed rotated grid offsets Return Code: BLACK_PIXEL - pixel intensity for BLACK WHITE_PIXEL - pixel intensity of WHITE **************************************************************************/ int dirbinarize(const unsigned char *pptr, const int idir, const ROTGRIDS *dirbingrids) { int gx, gy, gi, cy; int gsum, csum = 0; int *grid; double dcy; /* Assign nickname pointer. */ grid = dirbingrids->grids[idir]; /* Calculate center (0-oriented) row in grid. */ dcy = (dirbingrids->grid_h-1)/(double)2.0; /* Need to truncate precision so that answers are consistent */ /* on different computer architectures when rounding doubles. */ dcy = trunc_dbl_precision(dcy, TRUNC_SCALE); cy = sround(dcy); /* Initialize grid's pixel offset index to zero. */ gi = 0; /* Initialize grid's pixel accumulator to zero */ gsum = 0; /* Foreach row in grid ... */ for(gy = 0; gy < dirbingrids->grid_h; gy++){ /* Initialize row pixel sum to zero. */ int rsum = 0; /* Foreach column in grid ... */ for(gx = 0; gx < dirbingrids->grid_w; gx++){ /* Accumulate next pixel along rotated row in grid. */ rsum += *(pptr+grid[gi]); /* Bump grid's pixel offset index. */ gi++; } /* Accumulate row sum into grid pixel sum. */ gsum += rsum; /* If current row is center row, then save row sum separately. */ if(gy == cy) csum = rsum; } /* If the center row sum treated as an average is less than the */ /* total pixel sum in the rotated grid ... */ if((csum * dirbingrids->grid_h) < gsum) /* Set the binary pixel to BLACK. */ return(BLACK_PIXEL); else /* Otherwise set the binary pixel to WHITE. */ return(WHITE_PIXEL); }
/************************************************************************* ************************************************************************** #cat: lfs2nist_format - Takes a minutiae data structure and converts #cat: the XYT minutiae attributes in LFS native #cat: representation to NIST internal representation Input: iminutiae - minutiae data structure iw - width (in pixels) of the grayscale image ih - height (in pixels) of the grayscale image Output: iminutiae - overwrite each minutia element in the minutiae data sturcture convernt to nist internal minutiae format **************************************************************************/ void lfs2nist_format(MINUTIAE *iminutiae, int iw, int ih) { int i, ox, oy, ot, oq; MINUTIA *minutia; for (i = 0; i < iminutiae->num; i++) { minutia = iminutiae->list[i]; lfs2nist_minutia_XYT(&ox, &oy, &ot, minutia, iw, ih); oq = sround(minutia->reliability * 100.0); minutia->x = ox; minutia->y = oy; minutia->direction = ot; minutia->reliability = (double)oq; } }
bool numericCast(T_IN in, T_OUT& out) { if (std::is_same<T_IN, T_OUT>::value) { out = static_cast<T_OUT>(in); return true; } if (std::is_integral<T_OUT>::value) in = static_cast<T_IN>(sround((double)in)); if ((std::is_same<T_OUT, double>::value) || (in <= static_cast<double>(std::numeric_limits<T_OUT>::max()) && in >= static_cast<double>(std::numeric_limits<T_OUT>::lowest()))) { out = static_cast<T_OUT>(in); return true; } return false; }
void snip_rot_subimage_interp(unsigned char *data, const int w, const int h, unsigned char *idata, const int iw, const int ih, const int cx, const int cy, const float ang, unsigned char pix) { float c, s, fx, fy, sfx, sfy; int x, y; float hw, hh; float lx, ly, hx, hy; float ilx, ily, ihx, ihy; float dlx, dly, dhx, dhy; float d1, d2, d3, d4; float w1, w2, w3, w4, sw; float sq2; int p1, p2, p3, p4; double x20 = 2.0; sq2 = sqrt(x20); hw = (float)iw / 2.0; hh = (float)ih / 2.0; c = cos(ang); s = sin(ang); sfx = (cx - (hw * c) - (hh * s)); sfy = (cy + (hw * s) - (hh * c)); for(y = 0; y < ih; y++, sfx += s, sfy += c) { for(x = 0, fx = sfx, fy = sfy; x < iw; x++, fx += c, fy -= s) { lx = (float)floor((double)fx); ly = (float)floor((double)fy); hx = (float)ceil((double)fx); hy = (float)ceil((double)fy); ilx = (int)lx; ily = (int)ly; ihx = (int)hx; ihy = (int)hy; if((ilx >= 0) && (ihx < w) && (ily >= 0) && (ihy < h)) { dlx = pow(fx-lx, 2.0); dly = pow(fy-ly, 2.0); dhx = pow(hx-fx, 2.0); dhy = pow(hy-fy, 2.0); d1 = sqrt(dlx+dly); d2 = sqrt(dhx+dly); d3 = sqrt(dlx+dhy); d4 = sqrt(dhx+dhy); w1 = 1.0 - (d1/sq2); w2 = 1.0 - (d2/sq2); w3 = 1.0 - (d3/sq2); w4 = 1.0 - (d4/sq2); sw = w1+w2+w3+w4; p1 = ilx + ily*w; p2 = ihx + ily*w; p3 = ilx + ihy*w; p4 = ihx + ihy*w; *idata = sround((w1*(float)data[p1] + w2*(float)data[p2] + w3*(float)data[p3] + w4*(float)data[p4])/sw); } else *idata = pix; idata++; } } }
/************************************************************************* ************************************************************************** #cat: init_rotgrids - Allocates and initializes a set of offsets that address #cat: individual rotated pixels within a grid. #cat: These rotated grids are used to conduct DFT analyses #cat: on blocks of input image data, and they are used #cat: in isotropic binarization. Input: iw - width (in pixels) of the input image ih - height (in pixels) of the input image pad - designates the number of pixels to be padded to the perimeter of the input image. May be passed as UNDEFINED, in which case the specific padding required by the rotated grids will be computed and returned in ROTGRIDS. start_dir_angle - angle from which rotations are to start ndirs - number of rotations to compute (within a semicircle) grid_w - width of the grid in pixels to be rotated grid_h - height of the grid in pixels to be rotated relative2 - designates whether pixel offsets whould be computed relative to the ORIGIN or the CENTER of the grid Output: optr - points to the allcated/initialized ROTGRIDS structure Return Code: Zero - successful completion Negative - system error **************************************************************************/ int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad, const double start_dir_angle, const int ndirs, const int grid_w, const int grid_h, const int relative2) { ROTGRIDS *rotgrids; double pi_offset, pi_incr; int dir, ix, iy, grid_size, pw, grid_pad, min_dim; int *grid; double diag, theta, cs, sn, cx, cy; double fxm, fym, fx, fy; int ixt, iyt; double pad; /* Allocate structure */ rotgrids = (ROTGRIDS *)malloc(sizeof(ROTGRIDS)); if(rotgrids == (ROTGRIDS *)NULL){ fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids\n"); return(-30); } /* Set rotgrid attributes */ rotgrids->ngrids = ndirs; rotgrids->grid_w = grid_w; rotgrids->grid_h = grid_h; rotgrids->start_angle = start_dir_angle; rotgrids->relative2 = relative2; /* Compute pad based on diagonal of the grid */ diag = sqrt((double)((grid_w*grid_w)+(grid_h*grid_h))); switch(relative2){ case RELATIVE2CENTER: /* Assumption: all grid centers reside in valid/allocated memory. */ pad = (diag-1)/(double)2.0; /* Need to truncate precision so that answers are consistent */ /* on different computer architectures when rounding doubles. */ pad = trunc_dbl_precision(pad, TRUNC_SCALE); grid_pad = sround(pad); break; case RELATIVE2ORIGIN: /* Assumption: all grid origins reside in valid/allocated memory. */ min_dim = min(grid_w, grid_h); /* Compute pad as difference between the smallest grid dimension */ /* and the diagonal distance of the grid. */ pad = (diag-min_dim)/(double)2.0; /* Need to truncate precision so that answers are consistent */ /* on different computer architectures when rounding doubles. */ pad = trunc_dbl_precision(pad, TRUNC_SCALE); grid_pad = sround(pad); break; default: fprintf(stderr, "ERROR : init_rotgrids : Illegal relative flag : %d\n", relative2); free(rotgrids); return(-31); } /* If input padding is UNDEFINED ... */ if(ipad == UNDEFINED) /* Use the padding specifically required by the rotated grids herein. */ rotgrids->pad = grid_pad; else{ /* Otherwise, input pad was specified, so check to make sure it is */ /* sufficiently large to handle the rotated grids herein. */ if(ipad < grid_pad){ /* If input pad is NOT large enough, then ERROR. */ fprintf(stderr, "ERROR : init_rotgrids : Pad passed is too small\n"); free(rotgrids); return(-32); } /* Otherwise, use the specified input pad in computing grid offsets. */ rotgrids->pad = ipad; } /* Total number of points in grid */ grid_size = grid_w * grid_h; /* Compute width of "padded" image */ pw = iw + (rotgrids->pad<<1); /* Center coord of grid (0-oriented). */ cx = (grid_w-1)/(double)2.0; cy = (grid_h-1)/(double)2.0; /* Allocate list of rotgrid pointers */ rotgrids->grids = (int **)malloc(ndirs * sizeof(int *)); if(rotgrids->grids == (int **)NULL){ /* Free memory allocated to this point. */ free(rotgrids); fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids->grids\n"); return(-33); } /* Pi_offset is the offset in radians from which angles are to begin. */ pi_offset = start_dir_angle; pi_incr = M_PI/(double)ndirs; /* if ndirs == 16, incr = 11.25 degrees */ /* For each direction to rotate a grid ... */ for (dir = 0, theta = pi_offset; dir < ndirs; dir++, theta += pi_incr) { /* Allocate a rotgrid */ rotgrids->grids[dir] = (int *)malloc(grid_size * sizeof(int)); if(rotgrids->grids[dir] == (int *)NULL){ /* Free memory allocated to this point. */ { int _j; for(_j = 0; _j < dir; _j++){ free(rotgrids->grids[_j]); }} free(rotgrids); fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids->grids[dir]\n"); return(-34); } /* Set pointer to current grid */ grid = rotgrids->grids[dir]; /* Compute cos and sin of current angle */ cs = cos(theta); sn = sin(theta); /* This next section of nested FOR loops precomputes a */ /* rotated grid. The rotation is set up to rotate a GRID_W X */ /* GRID_H grid on its center point at C=(Cx,Cy). The current */ /* pixel being rotated is P=(Ix,Iy). Therefore, we have a */ /* rotation transformation of point P about pivot point C. */ /* The rotation transformation about a pivot point in matrix */ /* form is: */ /* +- -+ | cos(T) sin(T) 0 | [Ix Iy 1] | -sin(T) cos(T) 0 | | (1-cos(T))*Cx + Cy*sin(T) (1-cos(T))*Cy - Cx*sin(T) 1 | +- -+ */ /* Multiplying the 2 matrices and combining terms yeilds the */ /* equations for rotated coordinates (Rx, Ry): */ /* Rx = Cx + (Ix - Cx)*cos(T) - (Iy - Cy)*sin(T) */ /* Ry = Cy + (Ix - Cx)*sin(T) + (Iy - Cy)*cos(T) */ /* */ /* Care has been taken to ensure that (for example) when */ /* BLOCKSIZE==24 the rotated indices stay within a centered */ /* 34X34 area. */ /* This is important for computing an accurate padding of */ /* the input image. The rotation occurs "in-place" so that */ /* outer pixels in the grid are mapped at times from */ /* adjoining blocks. As a result, to keep from accessing */ /* "unknown" memory or pixels wrapped from the other side of */ /* the image, the input image should first be padded by */ /* PAD=round((DIAG - BLOCKSIZE)/2.0) where DIAG is the */ /* diagonal distance of the grid. */ /* For example, when BLOCKSIZE==24, Dx=34, so PAD=5. */ /* Foreach each y coord in block ... */ for (iy = 0; iy < grid_h; ++iy) { /* Compute rotation factors dependent on Iy (include constant) */ fxm = -1.0 * ((iy - cy) * sn); fym = ((iy - cy) * cs); /* If offsets are to be relative to the grids origin, then */ /* we need to subtract CX and CY. */ if(relative2 == RELATIVE2ORIGIN){ fxm += cx; fym += cy; } /* foreach each x coord in block ... */ for (ix = 0; ix < grid_w; ++ix) { /* Now combine factors dependent on Iy with those of Ix */ fx = fxm + ((ix - cx) * cs); fy = fym + ((ix - cx) * sn); /* Need to truncate precision so that answers are consistent */ /* on different computer architectures when rounding doubles. */ fx = trunc_dbl_precision(fx, TRUNC_SCALE); fy = trunc_dbl_precision(fy, TRUNC_SCALE); ixt = sround(fx); iyt = sround(fy); /* Store the current pixels relative */ /* rotated offset. Make sure to */ /* multiply the y-component of the */ /* offset by the "padded" image width! */ *grid++ = ixt + (iyt * pw); }/* ix */ }/* iy */ }/* dir */ *optr = rotgrids; return(0); }
/************************************************************************* ************************************************************************** #cat: get_max_padding_V2 - Deterines the maximum amount of image pixel padding #cat: required by all LFS (Version 2) processes. Padding is currently #cat: required by the rotated grids used in DFT analyses and in #cat: directional binarization. The NIST generalized code enables #cat: the parameters governing these processes to be redefined, so a #cat: check at runtime is required to determine which process #cat: requires the most padding. By using the maximum as the padding #cat: factor, all processes will run safely with a single padding of #cat: the input image avoiding the need to repad for further processes. Input: map_windowsize - the size (in pixels) of each window centered about each block in the image used in DFT analyses map_windowoffset - the offset (in pixels) from the orgin of the surrounding window to the origin of the block dirbin_grid_w - the width (in pixels) of the rotated grids used in directional binarization dirbin_grid_h - the height (in pixels) of the rotated grids used in directional binarization Return Code: Non-negative - the maximum padding required for all processes **************************************************************************/ int get_max_padding_V2(const int map_windowsize, const int map_windowoffset, const int dirbin_grid_w, const int dirbin_grid_h) { int dft_pad, dirbin_pad, max_pad; double diag; double pad; /* 1. Compute pad required for rotated windows used in DFT analyses. */ /* Explanation of DFT padding: B--------------------- | window | | | | | | A.......______|__________ | : : | |<-C-->: block: | <--|--D-->: : | image | ........ | | | | | | | | | | ---------------------- | | | Pixel A = Origin of entire fingerprint image = Also origin of first block in image. Each pixel in this block gets the same DFT results computed from the surrounding window. Note that in general blocks are adjacent and non-overlapping. Pixel B = Origin of surrounding window in which DFT analysis is conducted. Note that this window is not completely contained in the image but extends to the top and to the right. Distance C = Number of pixels in which the window extends beyond the image (map_windowoffset). Distance D = Amount of padding required to hold the entire rotated window in memory. */ /* Compute pad as difference between the MAP windowsize */ /* and the diagonal distance of the window. */ /* (DFT grids are computed with pixel offsets RELATIVE2ORIGIN.) */ diag = sqrt((double)(2.0 * map_windowsize * map_windowsize)); pad = (diag-map_windowsize)/(double)2.0; /* Need to truncate precision so that answers are consistent */ /* on different computer architectures when rounding doubles. */ pad = trunc_dbl_precision(pad, TRUNC_SCALE); /* Must add the window offset to the rotational padding. */ dft_pad = sround(pad) + map_windowoffset; /* 2. Compute pad required for rotated blocks used in directional */ /* binarization. Binarization blocks are applied to each pixel */ /* in the input image. */ diag = sqrt((double)((dirbin_grid_w*dirbin_grid_w)+ (dirbin_grid_h*dirbin_grid_h))); /* Assumption: all grid centers reside in valid/allocated memory. */ /* (Dirbin grids are computed with pixel offsets RELATIVE2CENTER.) */ pad = (diag-1)/(double)2.0; /* Need to truncate precision so that answers are consistent */ /* on different computer architectures when rounding doubles. */ pad = trunc_dbl_precision(pad, TRUNC_SCALE); dirbin_pad = sround(pad); max_pad = max(dft_pad, dirbin_pad); /* Return the maximum of the two required paddings. This padding will */ /* be sufficiently large for all purposes, so that padding of the */ /* input image will only be required once. */ return(max_pad); }
/************************************************************************* ************************************************************************** #cat: search_in_direction - Takes a specified maximum number of steps in a #cat: specified direction looking for the first occurence of #cat: a pixel with specified value. (Once found, adjustments #cat: are potentially made to make sure the resulting pixel #cat: and its associated edge pixel are 4-connected.) Input: pix - value of pixel to be searched for strt_x - x-pixel coord to start search strt_y - y-pixel coord to start search delta_x - increment in x for each step delta_y - increment in y for each step maxsteps - maximum number of steps to conduct search bdata - binary image data (0==while & 1==black) iw - width (in pixels) of image ih - height (in pixels) of image Output: ox - x coord of located pixel oy - y coord of located pixel oex - x coord of associated edge pixel oey - y coord of associated edge pixel Return Code: TRUE - pixel of specified value found FALSE - pixel of specified value NOT found **************************************************************************/ int search_in_direction(int *ox, int *oy, int *oex, int *oey, const int pix, const int strt_x, const int strt_y, const double delta_x, const double delta_y, const int maxsteps, unsigned char *bdata, const int iw, const int ih) { int i, x, y, px, py; double fx, fy; /* Set previous point to starting point. */ px = strt_x; py = strt_y; /* Set floating point accumulators to starting point. */ fx = (double)strt_x; fy = (double)strt_y; /* Foreach step up to the specified maximum ... */ for(i = 0; i < maxsteps; i++){ /* Increment accumulators. */ fx += delta_x; fy += delta_y; /* Round to get next step. */ x = sround(fx); y = sround(fy); /* If we stepped outside the image boundaries ... */ if((x < 0) || (x >= iw) || (y < 0) || (y >= ih)){ /* Return FALSE (we did not find what we were looking for). */ *ox = -1; *oy = -1; *oex = -1; *oey = -1; return(FALSE); } /* Otherwise, test to see if we found our pixel with value 'pix'. */ if(*(bdata+(y*iw)+x) == pix){ /* The previous and current pixels form a feature, edge pixel */ /* pair, which we would like to use for edge following. The */ /* previous pixel may be a diagonal neighbor however to the */ /* current pixel, in which case the pair could not be used by */ /* the contour tracing (which requires the edge pixel in the */ /* pair neighbor to the N,S,E or W. */ /* This routine adjusts the pair so that the results may be */ /* used by the contour tracing. */ fix_edge_pixel_pair(&x, &y, &px, &py, bdata, iw, ih); /* Return TRUE (we found what we were looking for). */ *ox = x; *oy = y; *oex = px; *oey = py; return(TRUE); } /* Otherwise, still haven't found pixel with desired value, */ /* so set current point to previous and take another step. */ px = x; py = y; } /* Return FALSE (we did not find what we were looking for). */ *ox = -1; *oy = -1; *oex = -1; *oey = -1; return(FALSE); }
int main(int argc, char *argv[]) { unsigned char *data, **pdata, *filename; int ret, i, w, h, d, img_type, dlen; seg_rec_coords *fing_boxes; int ppi, lossyflag = 0; int nf; procargs(argc, argv); if (old_style_args_flag) { /* This code supports the old-style invocation using 7 arguments and allowing different kinds of image files. */ /* FGP 1-12 is single finger : 13-14 four finger slaps : 15 for two thumbs : Craig said it would be good to eliminate 23 and use 15 instead. -- jck */ if(fgp < 1 && fgp > 14 && fgp != 15) { fprintf(stderr, "ERROR: %s: Invalid FGP (%d). " "Expecting 1-14 or 15 (Two thumbs)\n", argv[0], fgp); exit(-2); } if(fgp < 15 && fgp > 12) nf = 4; else if(fgp == 15) nf = 2; else nf = 1; /* READ THE INPUT FILE */ if((ret = read_and_decode_grayscale_image(ifile, &img_type, &data, &dlen, &w, &h, &d, &ppi))) exit(ret); /* TRY TO SEGMENT FINGER IMAGE */ if((ret = segment_fingers(data, w, h, &fing_boxes, nf, fgp, bthr_adj, rot_search))) exit(ret); /* PARSE FINGERS FROM ORIGINAL FINGER IMAGE */ if((ret = parse_segfing(&pdata, data, w, h, fing_boxes, nf, rot_seg))) exit(ret); free(data); /* OUTPUT RESULTS TO FILE */ filename = basename(ifile); if((ret = write_parsefing(filename, -1, fgp, comp, ppi, lossyflag, pdata, fing_boxes, nf, rot_seg))) exit(ret); free(fing_boxes); for(i = 0; i < nf; i++) free(pdata[i]); free(pdata); /* End of code supporting old-style interface. */ } else { /* ANSI/NIST file */ /* This code, from here to the end, supports the new-style interface for processing several images within ANSI/NIST files. */ ANSI_NIST *ansi_nist, *new_ansi_nist; RECORD *imgrecord; FIELD *impfield, *fgpfield; char *fgp_str, *endp; int rec_i, imgrecord_i, img_id, impfield_i, imp, matches = 0; double ppmm; int img_fgp, img_bthr_adj; /* per-image values */ char *filename; if (read_ANSI_NIST_file(ifile, &ansi_nist) < 0) exit(EXIT_FAILURE); if (ofile != NULL) { if (copy_ANSI_NIST(&new_ansi_nist, ansi_nist) < 0) exit(EXIT_FAILURE); } if (NULL == (filename = malloc(strlen(ifile)+1))) { fprintf(stderr, "ERROR : cannot allocate %d bytes for filename %s\n", strlen(ifile)+1, ifile); exit(EXIT_FAILURE); } /* this loop's index jumps from one grayprint to the next */ for ( rec_i = 1; (ret = lookup_ANSI_NIST_grayprint(&imgrecord, &imgrecord_i, rec_i, ansi_nist)) > 0; rec_i = imgrecord_i + 1 ) { /* Skip latent images. */ if (!lookup_IMP_field(&impfield, &impfield_i, imgrecord)) continue; imp = (int)strtol((char *)impfield->subfields[0]->items[0]->value, &endp, 10); if ('\0' != *endp) { fprintf(stderr, "ERROR : main : corrupt IMP value: %s\n", (char *)impfield->subfields[0]->items[0]->value); exit(EXIT_FAILURE); } if (imp_is_latent(imp)) continue; /* Skip records that don't match our command-line criteria. */ if (select_ANSI_NIST_record(imgrecord, opt_rec_sel) <= 0) continue; /* If we get this far it's the right kind of image. */ ++matches; /* Figure out the finger position code. */ if (TYPE_4_ID == imgrecord->type) { img_id = BIN_IMAGE_ID; fgpfield = imgrecord->fields[FGP_ID-1]; } else if (TYPE_14_ID == imgrecord->type) { img_id = DAT2_ID; fgpfield = imgrecord->fields[FGP3_ID-1]; } else { fprintf(stderr, "WARNING : main : skipped unexpected record type " "index %d, Type-%u\n", imgrecord_i+1, imgrecord->type); continue; } if (UNSET == fgp) { if ( fgpfield->subfields[0]->num_items > 1 && (TYPE_14_ID == imgrecord->type || strtol((char *)fgpfield->subfields[0]->items[1]->value, &endp, 10) != 255) ) { if ('\0' != *endp) { fprintf(stderr, "ERROR : main : corrupt FGP value: %s\n", (char *)fgpfield->subfields[0]->items[1]->value); exit(EXIT_FAILURE); } fprintf(stderr, "WARNING : main : multiple items in subfield, " " using only the first, [%d.%u.1] [Type-%u.03%u]\n", imgrecord_i+1, fgpfield->field_int+1, imgrecord->type, fgpfield->field_int+1); } fgp_str = (char *)fgpfield->subfields[0]->items[0]->value; img_fgp = strtol(fgp_str, &endp, 10); if ('\0' != *endp) { fprintf(stderr, "WARNING : main : currupt FGP value: %s\n", fgp_str); exit(EXIT_FAILURE); } } else { img_fgp = fgp; } /* Determine expected number of fingers in image. */ if (19 == img_fgp) /* ignore TIP or EJI images */ continue; else if (img_fgp == 13 || img_fgp == 14) nf = 4; else if (15 == img_fgp) nf = 2; else nf = 1; /* Turn on binary threshold adjustment for non-livescan prints, assuming they are from inked-paper. */ if (UNSET == bthr_adj) { img_bthr_adj = !imp_is_live_scan(imp); } else { img_bthr_adj = bthr_adj; } if (UNSET == comp) comp = 0; /* default compression */ if (UNSET == rot_search) rot_search = 0; /* default search rotation */ if (UNSET == rot_seg) rot_seg = 0; /* default output rotation */ if (verbose) fprintf(stderr, "record index %d, Type-%u, fgp=%d, nf=%d, " "imp=%d, bthr_adj=%d, rot_search=%d, comp=%d, rot_seg=%d\n", imgrecord_i+1, imgrecord->type, img_fgp, nf, imp, img_bthr_adj, rot_search, comp, rot_seg); ret = decode_ANSI_NIST_image(&data, &w, &h, &d, &ppmm, ansi_nist, imgrecord_i, 1); if (ret < 0) exit(EXIT_FAILURE); else if (0 == ret) continue; /* unsuitable image ignored */ ppi = sround(ppmm * MM_PER_INCH); if (segment_fingers(data, w, h, &fing_boxes, nf, img_fgp, img_bthr_adj, rot_search)) exit(EXIT_FAILURE); if (parse_segfing(&pdata, data, w, h, fing_boxes, nf, rot_seg)) exit(EXIT_FAILURE); if (ofile != NULL) { /* Convert Type-4 to 14 if necessary. */ if (TYPE_4_ID == imgrecord->type) { RECORD *new_imgrecord; ret = iafis2nist_fingerprint(&new_imgrecord, new_ansi_nist, imgrecord_i); if (ret < 0) exit(EXIT_FAILURE); else if (ret > 0) { if (insert_ANSI_NIST_record_frmem(imgrecord_i, new_imgrecord, new_ansi_nist)) exit(EXIT_FAILURE); if (delete_ANSI_NIST_record(imgrecord_i+1, new_ansi_nist)) exit(EXIT_FAILURE); } } if (insert_parsefing(new_ansi_nist, imgrecord_i, img_fgp, fing_boxes, nf, rot_search)) exit(EXIT_FAILURE); } if (output_images) { /* write_parsefing calls fileroot, which is destructive */ strcpy(filename, ifile); if (write_parsefing(basename(filename), imgrecord_i, img_fgp, comp, ppi, lossyflag, pdata, fing_boxes, nf, rot_seg)) exit(EXIT_FAILURE); } /* clean up before the next time around */ free(data); free(fing_boxes); for(i = 0; i < nf; i++) free(pdata[i]); free(pdata); } if (0 == matches) fprintf(stderr, "WARNING : nfseg : no images match the criteria\n"); if (ret < 0) exit(EXIT_FAILURE); if (ofile != NULL && write_ANSI_NIST_file(ofile, new_ansi_nist) < 0) exit(EXIT_FAILURE); } return(EXIT_SUCCESS); }