binar.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*******************************************************************************
  2. License:
  3. This software and/or related materials was developed at the National Institute
  4. of Standards and Technology (NIST) by employees of the Federal Government
  5. in the course of their official duties. Pursuant to title 17 Section 105
  6. of the United States Code, this software is not subject to copyright
  7. protection and is in the public domain.
  8. This software and/or related materials have been determined to be not subject
  9. to the EAR (see Part 734.3 of the EAR for exact details) because it is
  10. a publicly available technology and software, and is freely distributed
  11. to any interested party with no licensing requirements. Therefore, it is
  12. permissible to distribute this software as a free download from the internet.
  13. Disclaimer:
  14. This software and/or related materials was developed to promote biometric
  15. standards and biometric technology testing for the Federal Government
  16. in accordance with the USA PATRIOT Act and the Enhanced Border Security
  17. and Visa Entry Reform Act. Specific hardware and software products identified
  18. in this software were used in order to perform the software development.
  19. In no case does such identification imply recommendation or endorsement
  20. by the National Institute of Standards and Technology, nor does it imply that
  21. the products and equipment identified are necessarily the best available
  22. for the purpose.
  23. This software and/or related materials are provided "AS-IS" without warranty
  24. of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY,
  25. NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY
  26. or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the
  27. licensed product, however used. In no event shall NIST be liable for any
  28. damages and/or costs, including but not limited to incidental or consequential
  29. damages of any kind, including economic damage or injury to property and lost
  30. profits, regardless of whether NIST shall be advised, have reason to know,
  31. or in fact shall know of the possibility.
  32. By using this software, you agree to bear all risk relating to quality,
  33. use and performance of the software and/or related materials. You agree
  34. to hold the Government harmless from any claim arising from your use
  35. of the software.
  36. *******************************************************************************/
  37. /***********************************************************************
  38. LIBRARY: LFS - NIST Latent Fingerprint System
  39. FILE: BINAR.C
  40. AUTHOR: Michael D. Garris
  41. DATE: 03/16/1999
  42. UPDATED: 10/04/1999 Version 2 by MDG
  43. UPDATED: 03/16/2005 by MDG
  44. Contains routines responsible for binarizing a grayscale image based
  45. on an arbitrarily-sized image and its precomputed direcitonal ridge
  46. flow (IMAP) as part of the NIST Latent Fingerprint System (LFS).
  47. ***********************************************************************
  48. ROUTINES:
  49. binarize()
  50. binarize_V2()
  51. binarize_image()
  52. binarize_image_V2()
  53. dirbinarize()
  54. isobinarize()
  55. ***********************************************************************/
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #include "lfs.h"
  59. /*************************************************************************
  60. **************************************************************************
  61. #cat: binarize - Takes a padded grayscale input image and its associated ridge
  62. #cat: direction flow NMAP and produces a binarized version of the
  63. #cat: image. It then fills horizontal and vertical "holes" in the
  64. #cat: binary image results.
  65. Input:
  66. pdata - padded input grayscale image
  67. pw - padded width (in pixels) of input image
  68. ph - padded height (in pixels) of input image
  69. nmap - 2-D vector of IMAP directions and other codes
  70. mw - width (in blocks) of the NMAP
  71. mh - height (in blocks) of the NMAP
  72. dirbingrids - set of rotated grid offsets used for directional
  73. binarization
  74. lfsparms - parameters and thresholds for controlling LFS
  75. Output:
  76. optr - points to created (unpadded) binary image
  77. ow - width of binary image
  78. oh - height of binary image
  79. Return Code:
  80. Zero - successful completion
  81. Negative - system error
  82. **************************************************************************/
  83. int binarize(unsigned char **optr, int *ow, int *oh,
  84. unsigned char *pdata, const int pw, const int ph,
  85. int *nmap, const int mw, const int mh,
  86. const ROTGRIDS *dirbingrids, const LFSPARMS *lfsparms)
  87. {
  88. unsigned char *bdata;
  89. int i, bw, bh, ret; /* return code */
  90. /* 1. Binarize the padded input image using NMAP information. */
  91. if((ret = binarize_image(&bdata, &bw, &bh, pdata, pw, ph,
  92. nmap, mw, mh, lfsparms->blocksize,
  93. dirbingrids, lfsparms->isobin_grid_dim))){
  94. return(ret);
  95. }
  96. /* 2. Fill black and white holes in binary image. */
  97. /* LFS scans the binary image, filling holes, 3 times. */
  98. for(i = 0; i < lfsparms->num_fill_holes; i++)
  99. fill_holes(bdata, bw, bh);
  100. /* Return binarized input image. */
  101. *optr = bdata;
  102. *ow = bw;
  103. *oh = bh;
  104. return(0);
  105. }
  106. /*************************************************************************
  107. **************************************************************************
  108. #cat: binarize_V2 - Takes a padded grayscale input image and its associated
  109. #cat: Direction Map and produces a binarized version of the
  110. #cat: image. It then fills horizontal and vertical "holes" in
  111. #cat: the binary image results. Note that the input image must
  112. #cat: be padded sufficiently to contain in memory rotated
  113. #cat: directional binarization grids applied to pixels along the
  114. #cat: perimeter of the input image.
  115. Input:
  116. pdata - padded input grayscale image
  117. pw - padded width (in pixels) of input image
  118. ph - padded height (in pixels) of input image
  119. direction_map - 2-D vector of discrete ridge flow directions
  120. mw - width (in blocks) of the map
  121. mh - height (in blocks) of the map
  122. dirbingrids - set of rotated grid offsets used for directional
  123. binarization
  124. lfsparms - parameters and thresholds for controlling LFS
  125. Output:
  126. odata - points to created (unpadded) binary image
  127. ow - width of binary image
  128. oh - height of binary image
  129. Return Code:
  130. Zero - successful completion
  131. Negative - system error
  132. **************************************************************************/
  133. int binarize_V2(unsigned char **odata, int *ow, int *oh,
  134. unsigned char *pdata, const int pw, const int ph,
  135. int *direction_map, const int mw, const int mh,
  136. const ROTGRIDS *dirbingrids, const LFSPARMS *lfsparms)
  137. {
  138. unsigned char *bdata;
  139. int i, bw, bh, ret; /* return code */
  140. /* 1. Binarize the padded input image using directional block info. */
  141. if((ret = binarize_image_V2(&bdata, &bw, &bh, pdata, pw, ph,
  142. direction_map, mw, mh,
  143. lfsparms->blocksize, dirbingrids))){
  144. return(ret);
  145. }
  146. /* 2. Fill black and white holes in binary image. */
  147. /* LFS scans the binary image, filling holes, 3 times. */
  148. for(i = 0; i < lfsparms->num_fill_holes; i++)
  149. fill_holes(bdata, bw, bh);
  150. /* Return binarized input image. */
  151. *odata = bdata;
  152. *ow = bw;
  153. *oh = bh;
  154. return(0);
  155. }
  156. /*************************************************************************
  157. **************************************************************************
  158. #cat: binarize_image - Takes a grayscale input image and its associated
  159. #cat: NMAP and generates a binarized version of the image.
  160. Input:
  161. pdata - padded input grayscale image
  162. pw - padded width (in pixels) of input image
  163. ph - padded height (in pixels) of input image
  164. nmap - 2-D vector of IMAP directions and other codes
  165. mw - width (in blocks) of the NMAP
  166. mh - height (in blocks) of the NMAP
  167. imap_blocksize - dimension (in pixels) of each NMAP block
  168. dirbingrids - set of rotated grid offsets used for directional
  169. binarization
  170. isobin_grid_dim - dimension (in pixels) of grid used for isotropic
  171. binarization
  172. Output:
  173. optr - points to binary image results
  174. ow - points to binary image width
  175. oh - points to binary image height
  176. Return Code:
  177. Zero - successful completion
  178. Negative - system error
  179. **************************************************************************/
  180. int binarize_image(unsigned char **optr, int *ow, int *oh,
  181. unsigned char *pdata, const int pw, const int ph,
  182. const int *nmap, const int mw, const int mh,
  183. const int imap_blocksize, const ROTGRIDS *dirbingrids,
  184. const int isobin_grid_dim)
  185. {
  186. int ix, iy, bw, bh, bx, by, nmapval;
  187. unsigned char *bdata, *bptr;
  188. unsigned char *pptr, *spptr;
  189. /* Compute dimensions of "unpadded" binary image results. */
  190. bw = pw - (dirbingrids->pad<<1);
  191. bh = ph - (dirbingrids->pad<<1);
  192. bdata = (unsigned char *)malloc(bw*bh*sizeof(unsigned char));
  193. if(bdata == (unsigned char *)NULL){
  194. fprintf(stderr, "ERROR : binarize_image : malloc : bdata\n");
  195. return(-110);
  196. }
  197. bptr = bdata;
  198. spptr = pdata + (dirbingrids->pad * pw) + dirbingrids->pad;
  199. for(iy = 0; iy < bh; iy++){
  200. /* Set pixel pointer to start of next row in grid. */
  201. pptr = spptr;
  202. for(ix = 0; ix < bw; ix++){
  203. /* Compute which block the current pixel is in. */
  204. bx = (int)(ix/imap_blocksize);
  205. by = (int)(iy/imap_blocksize);
  206. /* Get corresponding value in NMAP */
  207. nmapval = *(nmap + (by*mw) + bx);
  208. /* If current block has no neighboring blocks with */
  209. /* VALID directions ... */
  210. if(nmapval == NO_VALID_NBRS)
  211. /* Set binary pixel to white (255). */
  212. *bptr = WHITE_PIXEL;
  213. /* Otherwise, if block's NMAP has a valid direction ... */
  214. else if(nmapval >= 0)
  215. /* Use directional binarization based on NMAP direction. */
  216. *bptr = dirbinarize(pptr, nmapval, dirbingrids);
  217. else
  218. /* Otherwise, the block's NMAP is either INVALID or */
  219. /* HIGH-CURVATURE, so use isotropic binarization. */
  220. *bptr = isobinarize(pptr, pw, ph, isobin_grid_dim);
  221. /* Bump input and output pixel pointers. */
  222. pptr++;
  223. bptr++;
  224. }
  225. /* Bump pointer to the next row in padded input image. */
  226. spptr += pw;
  227. }
  228. *optr = bdata;
  229. *ow = bw;
  230. *oh = bh;
  231. return(0);
  232. }
  233. /*************************************************************************
  234. **************************************************************************
  235. #cat: binarize_image_V2 - Takes a grayscale input image and its associated
  236. #cat: Direction Map and generates a binarized version of the
  237. #cat: image. Note that there is no "Isotropic" binarization
  238. #cat: used in this version.
  239. Input:
  240. pdata - padded input grayscale image
  241. pw - padded width (in pixels) of input image
  242. ph - padded height (in pixels) of input image
  243. direction_map - 2-D vector of discrete ridge flow directions
  244. mw - width (in blocks) of the map
  245. mh - height (in blocks) of the map
  246. blocksize - dimension (in pixels) of each NMAP block
  247. dirbingrids - set of rotated grid offsets used for directional
  248. binarization
  249. Output:
  250. odata - points to binary image results
  251. ow - points to binary image width
  252. oh - points to binary image height
  253. Return Code:
  254. Zero - successful completion
  255. Negative - system error
  256. **************************************************************************/
  257. int binarize_image_V2(unsigned char **odata, int *ow, int *oh,
  258. unsigned char *pdata, const int pw, const int ph,
  259. const int *direction_map, const int mw, const int mh,
  260. const int blocksize, const ROTGRIDS *dirbingrids)
  261. {
  262. int ix, iy, bw, bh, bx, by, mapval;
  263. unsigned char *bdata, *bptr;
  264. unsigned char *pptr, *spptr;
  265. /* Compute dimensions of "unpadded" binary image results. */
  266. bw = pw - (dirbingrids->pad<<1);
  267. bh = ph - (dirbingrids->pad<<1);
  268. bdata = (unsigned char *)malloc(bw*bh*sizeof(unsigned char));
  269. if(bdata == (unsigned char *)NULL){
  270. fprintf(stderr, "ERROR : binarize_image_V2 : malloc : bdata\n");
  271. return(-600);
  272. }
  273. bptr = bdata;
  274. spptr = pdata + (dirbingrids->pad * pw) + dirbingrids->pad;
  275. for(iy = 0; iy < bh; iy++){
  276. /* Set pixel pointer to start of next row in grid. */
  277. pptr = spptr;
  278. for(ix = 0; ix < bw; ix++){
  279. /* Compute which block the current pixel is in. */
  280. bx = (int)(ix/blocksize);
  281. by = (int)(iy/blocksize);
  282. /* Get corresponding value in Direction Map. */
  283. mapval = *(direction_map + (by*mw) + bx);
  284. /* If current block has has INVALID direction ... */
  285. if(mapval == INVALID_DIR)
  286. /* Set binary pixel to white (255). */
  287. *bptr = WHITE_PIXEL;
  288. /* Otherwise, if block has a valid direction ... */
  289. else /*if(mapval >= 0)*/
  290. /* Use directional binarization based on block's direction. */
  291. *bptr = dirbinarize(pptr, mapval, dirbingrids);
  292. /* Bump input and output pixel pointers. */
  293. pptr++;
  294. bptr++;
  295. }
  296. /* Bump pointer to the next row in padded input image. */
  297. spptr += pw;
  298. }
  299. *odata = bdata;
  300. *ow = bw;
  301. *oh = bh;
  302. return(0);
  303. }
  304. /*************************************************************************
  305. **************************************************************************
  306. #cat: dirbinarize - Determines the binary value of a grayscale pixel based
  307. #cat: on a VALID IMAP ridge flow direction.
  308. CAUTION: The image to which the input pixel points must be appropriately
  309. padded to account for the radius of the rotated grid. Otherwise,
  310. this routine may access "unkown" memory.
  311. Input:
  312. pptr - pointer to current grayscale pixel
  313. idir - IMAP integer direction associated with the block the
  314. current is in
  315. dirbingrids - set of precomputed rotated grid offsets
  316. Return Code:
  317. BLACK_PIXEL - pixel intensity for BLACK
  318. WHITE_PIXEL - pixel intensity of WHITE
  319. **************************************************************************/
  320. int dirbinarize(const unsigned char *pptr, const int idir,
  321. const ROTGRIDS *dirbingrids)
  322. {
  323. int gx, gy, gi, cy;
  324. int rsum, gsum, csum = 0;
  325. int *grid;
  326. double dcy;
  327. /* Assign nickname pointer. */
  328. grid = dirbingrids->grids[idir];
  329. /* Calculate center (0-oriented) row in grid. */
  330. dcy = (dirbingrids->grid_h-1)/(double)2.0;
  331. /* Need to truncate precision so that answers are consistent */
  332. /* on different computer architectures when rounding doubles. */
  333. dcy = trunc_dbl_precision(dcy, TRUNC_SCALE);
  334. cy = sround(dcy);
  335. /* Initialize grid's pixel offset index to zero. */
  336. gi = 0;
  337. /* Initialize grid's pixel accumulator to zero */
  338. gsum = 0;
  339. /* Foreach row in grid ... */
  340. for(gy = 0; gy < dirbingrids->grid_h; gy++){
  341. /* Initialize row pixel sum to zero. */
  342. rsum = 0;
  343. /* Foreach column in grid ... */
  344. for(gx = 0; gx < dirbingrids->grid_w; gx++){
  345. /* Accumulate next pixel along rotated row in grid. */
  346. rsum += *(pptr+grid[gi]);
  347. /* Bump grid's pixel offset index. */
  348. gi++;
  349. }
  350. /* Accumulate row sum into grid pixel sum. */
  351. gsum += rsum;
  352. /* If current row is center row, then save row sum separately. */
  353. if(gy == cy)
  354. csum = rsum;
  355. }
  356. /* If the center row sum treated as an average is less than the */
  357. /* total pixel sum in the rotated grid ... */
  358. if((csum * dirbingrids->grid_h) < gsum)
  359. /* Set the binary pixel to BLACK. */
  360. return(BLACK_PIXEL);
  361. else
  362. /* Otherwise set the binary pixel to WHITE. */
  363. return(WHITE_PIXEL);
  364. }
  365. /*************************************************************************
  366. **************************************************************************
  367. #cat: isobinarize - Determines the binary value of a grayscale pixel based
  368. #cat: on comparing the grayscale value with a surrounding
  369. #cat: neighborhood grid of pixels. If the current pixel (treated
  370. #cat: as an average) is less than the sum of the pixels in
  371. #cat: the neighborhood, then the binary value is set to BLACK,
  372. #cat: otherwise it is set to WHITE. This binarization technique
  373. #cat: is used when there is no VALID IMAP direction for the
  374. #cat: block in which the current pixel resides.
  375. CAUTION: The image to which the input pixel points must be appropriately
  376. padded to account for the radius of the neighborhood. Otherwise,
  377. this routine may access "unkown" memory.
  378. Input:
  379. pptr - pointer to curent grayscale pixel
  380. pw - padded width (in pixels) of the grayscale image
  381. ph - padded height (in pixels) of the grayscale image
  382. isobin_grid_dim - dimension (in pixels) of the neighborhood
  383. Return Code:
  384. BLACK_PIXEL - pixel intensity for BLACK
  385. WHITE_PIXEL - pixel intensity of WHITE
  386. **************************************************************************/
  387. int isobinarize(unsigned char *pptr, const int pw, const int ph,
  388. const int isobin_grid_dim)
  389. {
  390. unsigned char *sptr, *cptr;
  391. int px, py;
  392. int radius;
  393. int bsum;
  394. double drad;
  395. /* Initialize grid pixel sum to zero. */
  396. bsum = 0;
  397. /* Compute radius from current pixel based on isobin_grid_dim. */
  398. drad = (isobin_grid_dim - 1)/(double)2.0;
  399. /* Need to truncate precision so that answers are consistent */
  400. /* on different computer architectures when rounding doubles. */
  401. drad = trunc_dbl_precision(drad, TRUNC_SCALE);
  402. radius = sround(drad);
  403. /* Set pointer to origin of grid centered on the current pixel. */
  404. sptr = pptr - (radius*pw) - radius;
  405. /* For each row in the grid ... */
  406. for(py = 0; py < isobin_grid_dim; py++){
  407. /* Set pixel pointer to start of next row in grid. */
  408. cptr = sptr;
  409. /* For each column in the grid ... */
  410. for(px = 0; px < isobin_grid_dim; px++){
  411. /* Accumulate next pixel in the grid. */
  412. bsum += *cptr;
  413. /* Bump pixel pointer. */
  414. cptr++;
  415. }
  416. /* Bump to the start of the next row in the grid. */
  417. sptr += pw;
  418. }
  419. /* If current (center) pixel when treated as an average for the */
  420. /* entire grid is less than the total pixel sum of the grid ... */
  421. if((*pptr * isobin_grid_dim * isobin_grid_dim) < bsum)
  422. /* Set the binary pixel to BLACK. */
  423. return(BLACK_PIXEL);
  424. else
  425. /* Otherwise, set the binary pixel to WHITE. */
  426. return(WHITE_PIXEL);
  427. }