| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /******************************************************************************* | ||
| 2 | |||
| 3 | License: | ||
| 4 | This software and/or related materials was developed at the National Institute | ||
| 5 | of Standards and Technology (NIST) by employees of the Federal Government | ||
| 6 | in the course of their official duties. Pursuant to title 17 Section 105 | ||
| 7 | of the United States Code, this software is not subject to copyright | ||
| 8 | protection and is in the public domain. | ||
| 9 | |||
| 10 | This software and/or related materials have been determined to be not subject | ||
| 11 | to the EAR (see Part 734.3 of the EAR for exact details) because it is | ||
| 12 | a publicly available technology and software, and is freely distributed | ||
| 13 | to any interested party with no licensing requirements. Therefore, it is | ||
| 14 | permissible to distribute this software as a free download from the internet. | ||
| 15 | |||
| 16 | Disclaimer: | ||
| 17 | This software and/or related materials was developed to promote biometric | ||
| 18 | standards and biometric technology testing for the Federal Government | ||
| 19 | in accordance with the USA PATRIOT Act and the Enhanced Border Security | ||
| 20 | and Visa Entry Reform Act. Specific hardware and software products identified | ||
| 21 | in this software were used in order to perform the software development. | ||
| 22 | In no case does such identification imply recommendation or endorsement | ||
| 23 | by the National Institute of Standards and Technology, nor does it imply that | ||
| 24 | the products and equipment identified are necessarily the best available | ||
| 25 | for the purpose. | ||
| 26 | |||
| 27 | This software and/or related materials are provided "AS-IS" without warranty | ||
| 28 | of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, | ||
| 29 | NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY | ||
| 30 | or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the | ||
| 31 | licensed product, however used. In no event shall NIST be liable for any | ||
| 32 | damages and/or costs, including but not limited to incidental or consequential | ||
| 33 | damages of any kind, including economic damage or injury to property and lost | ||
| 34 | profits, regardless of whether NIST shall be advised, have reason to know, | ||
| 35 | or in fact shall know of the possibility. | ||
| 36 | |||
| 37 | By using this software, you agree to bear all risk relating to quality, | ||
| 38 | use and performance of the software and/or related materials. You agree | ||
| 39 | to hold the Government harmless from any claim arising from your use | ||
| 40 | of the software. | ||
| 41 | |||
| 42 | *******************************************************************************/ | ||
| 43 | |||
| 44 | |||
| 45 | /*********************************************************************** | ||
| 46 | LIBRARY: LFS - NIST Latent Fingerprint System | ||
| 47 | |||
| 48 | FILE: CHAINCODE.C | ||
| 49 | AUTHOR: Michael D. Garris | ||
| 50 | DATE: 05/11/1999 | ||
| 51 | |||
| 52 | Contains routines responsible for generating and manipulating | ||
| 53 | chain codes as part of the NIST Latent Fingerprint System (LFS). | ||
| 54 | |||
| 55 | *********************************************************************** | ||
| 56 | ROUTINES: | ||
| 57 | chain_code_loop() | ||
| 58 | is_chain_clockwise() | ||
| 59 | ***********************************************************************/ | ||
| 60 | |||
| 61 | #include <stdio.h> | ||
| 62 | #include <lfs.h> | ||
| 63 | |||
| 64 | /************************************************************************* | ||
| 65 | ************************************************************************** | ||
| 66 | #cat: chain_code_loop - Converts a feature's contour points into an | ||
| 67 | #cat: 8-connected chain code vector. This encoding represents | ||
| 68 | #cat: the direction taken between each adjacent point in the | ||
| 69 | #cat: contour. Chain codes may be used for many purposes, such | ||
| 70 | #cat: as computing the perimeter or area of an object, and they | ||
| 71 | #cat: may be used in object detection and recognition. | ||
| 72 | |||
| 73 | Input: | ||
| 74 | contour_x - x-coord list for feature's contour points | ||
| 75 | contour_y - y-coord list for feature's contour points | ||
| 76 | ncontour - number of points in contour | ||
| 77 | Output: | ||
| 78 | ochain - resulting vector of chain codes | ||
| 79 | onchain - number of codes in chain | ||
| 80 | (same as number of points in contour) | ||
| 81 | Return Code: | ||
| 82 | Zero - chain code successful derived | ||
| 83 | Negative - system error | ||
| 84 | **************************************************************************/ | ||
| 85 | 167 | int chain_code_loop(int **ochain, int *onchain, | |
| 86 | const int *contour_x, const int *contour_y, const int ncontour) | ||
| 87 | { | ||
| 88 | 167 | int *chain; | |
| 89 | 167 | int i, j, dx, dy; | |
| 90 | |||
| 91 | /* If we don't have at least 3 points in the contour ... */ | ||
| 92 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 167 times.
|
167 | if(ncontour <= 3){ |
| 93 | /* Then we don't have a loop, so set chain length to 0 */ | ||
| 94 | /* and return without any allocations. */ | ||
| 95 | ✗ | *onchain = 0; | |
| 96 | ✗ | return(0); | |
| 97 | } | ||
| 98 | |||
| 99 | /* Allocate chain code vector. It will be the same length as the */ | ||
| 100 | /* number of points in the contour. There will be one chain code */ | ||
| 101 | /* between each point on the contour including a code between the */ | ||
| 102 | /* last to the first point on the contour (completing the loop). */ | ||
| 103 | 167 | chain = (int *)g_malloc(ncontour * sizeof(int)); | |
| 104 | |||
| 105 | /* For each neighboring point in the list (with "i" pointing to the */ | ||
| 106 | /* previous neighbor and "j" pointing to the next neighbor... */ | ||
| 107 |
2/2✓ Branch 0 (7→6) taken 1180 times.
✓ Branch 1 (7→8) taken 167 times.
|
1514 | for(i = 0, j=1; i < ncontour-1; i++, j++){ |
| 108 | /* Compute delta in X between neighbors. */ | ||
| 109 | 1180 | dx = contour_x[j] - contour_x[i]; | |
| 110 | /* Compute delta in Y between neighbors. */ | ||
| 111 | 1180 | dy = contour_y[j] - contour_y[i]; | |
| 112 | /* Derive chain code index from neighbor deltas. */ | ||
| 113 | /* The deltas are on the range [-1..1], so to use them as indices */ | ||
| 114 | /* into the code list, they must first be incremented by one. */ | ||
| 115 | 1180 | chain[i] = *(g_chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1); | |
| 116 | } | ||
| 117 | |||
| 118 | /* Now derive chain code between last and first points in the */ | ||
| 119 | /* contour list. */ | ||
| 120 | 167 | dx = contour_x[0] - contour_x[i]; | |
| 121 | 167 | dy = contour_y[0] - contour_y[i]; | |
| 122 | 167 | chain[i] = *(g_chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1); | |
| 123 | |||
| 124 | /* Store results to the output pointers. */ | ||
| 125 | 167 | *ochain = chain; | |
| 126 | 167 | *onchain = ncontour; | |
| 127 | |||
| 128 | /* Return normally. */ | ||
| 129 | 167 | return(0); | |
| 130 | } | ||
| 131 | |||
| 132 | /************************************************************************* | ||
| 133 | ************************************************************************** | ||
| 134 | #cat: is_chain_clockwise - Takes an 8-connected chain code vector and | ||
| 135 | #cat: determines if the codes are ordered clockwise or | ||
| 136 | #cat: counter-clockwise. | ||
| 137 | #cat: The routine also requires a default return value be | ||
| 138 | #cat: specified in the case the the routine is not able to | ||
| 139 | #cat: definitively determine the chains direction. This allows | ||
| 140 | #cat: the default response to be application-specific. | ||
| 141 | |||
| 142 | Input: | ||
| 143 | chain - chain code vector | ||
| 144 | nchain - number of codes in chain | ||
| 145 | default_ret - default return code (used when we can't tell the order) | ||
| 146 | Return Code: | ||
| 147 | TRUE - chain determined to be ordered clockwise | ||
| 148 | FALSE - chain determined to be ordered counter-clockwise | ||
| 149 | Default - could not determine the order of the chain | ||
| 150 | **************************************************************************/ | ||
| 151 | 167 | int is_chain_clockwise(const int *chain, const int nchain, | |
| 152 | const int default_ret) | ||
| 153 | { | ||
| 154 | 167 | int i, j, d, sum; | |
| 155 | |||
| 156 | /* Initialize turn-accumulator to 0. */ | ||
| 157 | 167 | sum = 0; | |
| 158 | |||
| 159 | /* Foreach neighboring code in chain, compute the difference in */ | ||
| 160 | /* direction and accumulate. Left-hand turns increment, whereas */ | ||
| 161 | /* right-hand decrement. */ | ||
| 162 |
2/2✓ Branch 0 (8→3) taken 1180 times.
✓ Branch 1 (8→9) taken 167 times.
|
1347 | for(i = 0, j =1; i < nchain-1; i++, j++){ |
| 163 | /* Compute delta in neighbor direction. */ | ||
| 164 | 1180 | d = chain[j] - chain[i]; | |
| 165 | /* Make the delta the "inner" distance. */ | ||
| 166 | /* If delta >= 4, for example if chain_i==2 and chain_j==7 (which */ | ||
| 167 | /* means the contour went from a step up to step down-to-the-right) */ | ||
| 168 | /* then 5=(7-2) which is >=4, so -3=(5-8) which means that the */ | ||
| 169 | /* change in direction is a righ-hand turn of 3 units). */ | ||
| 170 |
2/2✓ Branch 0 (3→4) taken 3 times.
✓ Branch 1 (3→5) taken 1177 times.
|
1180 | if(d >= 4) |
| 171 | 3 | d -= 8; | |
| 172 | /* If delta <= -4, for example if chain_i==7 and chain_j==2 (which */ | ||
| 173 | /* means the contour went from a step down-to-the-right to step up) */ | ||
| 174 | /* then -5=(2-7) which is <=-4, so 3=(-5+8) which means that the */ | ||
| 175 | /* change in direction is a left-hand turn of 3 units). */ | ||
| 176 |
2/2✓ Branch 0 (5→6) taken 169 times.
✓ Branch 1 (5→7) taken 1008 times.
|
1177 | else if (d <= -4) |
| 177 | 169 | d += 8; | |
| 178 | |||
| 179 | /* The delta direction is then accumulated. */ | ||
| 180 | 1180 | sum += d; | |
| 181 | } | ||
| 182 | |||
| 183 | /* Now we need to add in the final delta direction between the last */ | ||
| 184 | /* and first codes in the chain. */ | ||
| 185 | 167 | d = chain[0] - chain[i]; | |
| 186 |
1/2✗ Branch 0 (9→10) not taken.
✓ Branch 1 (9→11) taken 167 times.
|
167 | if(d >= 4) |
| 187 | ✗ | d -= 8; | |
| 188 |
2/2✓ Branch 0 (11→12) taken 1 times.
✓ Branch 1 (11→13) taken 166 times.
|
167 | else if (d <= -4) |
| 189 | 1 | d += 8; | |
| 190 | 167 | sum += d; | |
| 191 | |||
| 192 | /* If the final turn_accumulator == 0, then we CAN'T TELL the */ | ||
| 193 | /* direction of the chain code, so return the default return value. */ | ||
| 194 |
1/2✓ Branch 0 (13→14) taken 167 times.
✗ Branch 1 (13→16) not taken.
|
167 | if(sum == 0) |
| 195 | return(default_ret); | ||
| 196 | /* Otherwise, if the final turn-accumulator is positive ... */ | ||
| 197 |
1/2✗ Branch 0 (14→15) not taken.
✓ Branch 1 (14→16) taken 167 times.
|
167 | else if(sum > 0) |
| 198 | /* Then we had a greater amount of left-hand turns than right-hand */ | ||
| 199 | /* turns, so the chain is in COUNTER-CLOCKWISE order, so return FALSE. */ | ||
| 200 | return(FALSE); | ||
| 201 | /* Otherwise, the final turn-accumulator is negative ... */ | ||
| 202 | else | ||
| 203 | /* So we had a greater amount of right-hand turns than left-hand */ | ||
| 204 | /* turns, so the chain is in CLOCKWISE order, so return TRUE. */ | ||
| 205 | ✗ | return(TRUE); | |
| 206 | } | ||
| 207 |