Exemple #1
0
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;
      }
   }
}
Exemple #2
0
/*************************************************************************
**************************************************************************
#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;
}
Exemple #4
0
/*************************************************************************
**************************************************************************
#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;
}
Exemple #5
0
    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()));
    }
Exemple #6
0
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);
}
Exemple #7
0
/*************************************************************************
**************************************************************************
#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);
}
Exemple #8
0
/*************************************************************************
**************************************************************************
#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;
   }
}
Exemple #9
0
 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;
 }
Exemple #10
0
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);
}
Exemple #13
0
/*************************************************************************
**************************************************************************
#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);
}
Exemple #14
0
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);
}