1 /*########################################################################
3 * Copyright(C) 2002-2007. All Rights Reserved.
5 * Authors: Shivang Patel
8 * Changes: jdh -> Added support for ImageMagick that enables
9 * to export files to more than 40 formats.
10 * This is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2, or (at your option) any later
15 * This is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * You should have received a copy of the GNU General Public License with
21 * the fvs source package as the
22 * file COPYING. If not, write to the Free Software Foundation, Inc.,
23 * 59 Temple Place - Suite 330, Boston, MA
25 ########################################################################*/
26 // this code by pallav gupta (pallav@ieee.org)
28 // this algorithm is described in two papers.
30 // xudong jiang and wei-yun yau, "fingerprint minutiae matching based on the
31 //local and global structure
33 // shenglin yang and ingrid m. verbauwhede, "a secure fingerprint matching
44 static FvsInt_t
CompareLocalStructures(Fvs_LocalStructure_t
*ils
,
45 Fvs_LocalStructure_t
*tls
,
46 FvsInt_t ilen
, FvsInt_t tlen
);
48 static void FindMaxDistance(FvsMinutia_t
*src
, FvsInt_t
*neigh
, FvsInt_t ref
,
49 FvsFloat_t
*d
, FvsInt_t
*idx
);
50 static void FindNeighbors(FvsMinutia_t
*src
, FvsInt_t length
, FvsInt_t ineigh
[][NEIGHBORS
]);
51 static void ComputeLocalStructure(FvsMinutia_t
*src
, FvsInt_t length
,
52 FvsInt_t ineigh
[][NEIGHBORS
],
53 Fvs_LocalStructure_t
*ls
);
54 static inline FvsFloat_t
anglediff(FvsFloat_t a
, FvsFloat_t b
);
57 FvsError_t MatchingCompareMinutiaSets
59 const FvsMinutiaSet_t set1
,
60 const FvsMinutiaSet_t set2
,
64 FvsMinutia_t
*iminu
= MinutiaSetGetBuffer(set1
);
65 FvsInt_t nb_iminu
= MinutiaSetGetCount(set1
);
67 FvsMinutia_t
*tminu
= MinutiaSetGetBuffer(set2
);
68 FvsInt_t nb_tminu
= MinutiaSetGetCount(set2
);
70 FvsInt_t ineigh
[MAXMINUTIA
][NEIGHBORS
] = {};
71 FvsInt_t tneigh
[MAXMINUTIA
][NEIGHBORS
] = {};
73 Fvs_LocalStructure_t ls_iminu
[MAXMINUTIA
];
74 Fvs_LocalStructure_t ls_tminu
[MAXMINUTIA
];
76 FvsInt_t matched
, max
;
78 // find the neigherest neighbors
79 FindNeighbors(iminu
, nb_iminu
, ineigh
);
80 FindNeighbors(tminu
, nb_tminu
, tneigh
);
81 // compute the local structures of the minutia
82 ComputeLocalStructure(iminu
, nb_iminu
, ineigh
, ls_iminu
);
83 ComputeLocalStructure(tminu
, nb_tminu
, tneigh
, ls_tminu
);
84 matched
= CompareLocalStructures(ls_iminu
, ls_tminu
, nb_iminu
, nb_tminu
);
85 max
= (nb_iminu
> nb_tminu
) ? nb_iminu
: nb_tminu
;
86 (*pgoodness
) = (FvsFloat_t
)matched
/max
;
91 static FvsInt_t
CompareLocalStructures(Fvs_LocalStructure_t
*ils
,
92 Fvs_LocalStructure_t
*tls
,
93 FvsInt_t ilen
, FvsInt_t tlen
)
95 Fvs_LocalStructure_t s1
, s2
;
96 FvsInt_t marked
, matched
;
102 // one minutia from template
103 for (i
= 0; i
< ilen
; i
++) {
106 // one minutia from input
107 for (j
= 0; j
< tlen
; j
++) {
111 // need to go further only if the local ridge direction are similiar
112 if (fabs(s1
.angle
- s2
.angle
) > DELTA_ANGLE
)
117 // each neighbor of input minutia
118 for (k
= 0; k
< NEIGHBORS
; k
++) {
119 // each neighbor of template minutia
120 for (l
= 0; l
< NEIGHBORS
; l
++) {
122 if (fabs(s1
.distance
[k
] - s2
.distance
[l
]) > DELTA_DISTANCE
)
124 if (fabs(s1
.varphi
[k
] - s2
.varphi
[l
]) > DELTA_VARPHI
)
126 if (fabs(s1
.vartheta
[k
] - s2
.vartheta
[l
]) > DELTA_VARTHETA
)
128 // all conditions matched, consider k'th neighboer and l'th neighbor marked
133 if (marked
> THRESHOLD_MARKED
)
142 static void ComputeLocalStructure(FvsMinutia_t
*src
, FvsInt_t length
,
143 FvsInt_t ineigh
[][NEIGHBORS
], Fvs_LocalStructure_t
*ls
)
145 FvsFloat_t deltax
, deltay
, distance
;
148 for (i
= 0; i
< length
; i
++) {
149 for (j
= 0; j
< NEIGHBORS
; j
++) {
150 // get index of jth neighbor
154 deltax
= src
[p
].x
- src
[i
].x
;
155 deltay
= src
[p
].y
- src
[i
].y
;
156 distance
= sqrt(deltax
*deltax
+ deltay
*deltay
);
157 ls
[i
].distance
[j
] = distance
;
160 ls
[i
].varphi
[j
] = anglediff(src
[p
].angle
, src
[i
].angle
);
163 ls
[i
].vartheta
[j
] = anglediff(atan2(deltay
, deltax
), src
[i
].angle
);
166 ls
[i
].angle
= src
[i
].angle
;
171 static inline FvsFloat_t
anglediff(FvsFloat_t a
, FvsFloat_t b
)
177 if (dif
> -M_PI
&& dif
<= M_PI
)
179 else if (dif
<= -M_PI
)
180 return (2*M_PI
+ dif
);
182 return (2*M_PI
- dif
);
187 static void FindNeighbors(FvsMinutia_t
*src
, FvsInt_t length
, FvsInt_t ineigh
[][NEIGHBORS
])
190 FvsInt_t i
, j
, k
, idx
, end
, wrap
= 0;
191 FvsFloat_t deltax
, deltay
, distance
, maxdis
;
193 // find the neigherest neighbors for input minutia
194 for (i
= 0; i
< length
; i
++) {
195 // pick the first 6 points, aribtrarily
197 for (k
= 0; k
< NEIGHBORS
; k
++) {
205 // find the max distance
206 FindMaxDistance(src
, ineigh
[i
], i
, &maxdis
, &idx
);
208 end
= wrap
? i
: length
;
211 while (((src
[j
].x
- src
[i
].x
) < maxdis
) && (j
< end
) && (j
>= 0)) {
212 deltax
= src
[j
].x
- src
[i
].x
;
213 deltay
= src
[j
].y
- src
[i
].y
;
214 distance
= sqrt(deltax
*deltax
+ deltay
*deltay
);
216 if (distance
< maxdis
) {
218 FindMaxDistance(src
, ineigh
[i
], i
, &maxdis
, &idx
);
227 // only need to search backwards if when picking we didn't wrap around
228 // if we wrapped around searching upwards will have covered all points
231 while (((src
[i
].x
- src
[j
].x
) < maxdis
) && (j
>= 0)) {
232 deltax
= src
[i
].x
- src
[j
].x
;
233 deltay
= src
[i
].y
- src
[j
].y
;
234 distance
= sqrt(deltax
*deltax
+ deltay
*deltay
);
236 if (distance
< maxdis
) {
238 FindMaxDistance(src
, ineigh
[i
], i
, &maxdis
, &idx
);
246 static void FindMaxDistance(FvsMinutia_t
*src
, FvsInt_t
*neigh
, FvsInt_t ref
, FvsFloat_t
*d
,
249 FvsInt_t i
, maxi
= 0, p
= neigh
[0];
250 FvsFloat_t deltax
= src
[p
].x
- src
[ref
].x
;
251 FvsFloat_t deltay
= src
[p
].y
- src
[ref
].y
;
252 FvsFloat_t maxd
= sqrt(deltax
*deltax
+ deltay
*deltay
), tempd
;
254 // printf("origin: %f %f\n", src[ref].x, src[ref].y);
255 //printf("0: %f %f %f\n", src[p].x, src[p].y, tempd);
257 for (i
= 1; i
< NEIGHBORS
; i
++) {
259 deltax
= src
[p
].x
- src
[ref
].x
;
260 deltay
= src
[p
].y
- src
[ref
].y
;
261 tempd
= sqrt(deltax
*deltax
+ deltay
*deltay
);
262 //printf("%d: %f %f %f\n", i, src[p].x, src[p].y, tempd);
270 //printf("max = %f, idx = %d\n\n\n", maxd, maxi);
275 FvsError_t
MinutiaSetSort(FvsMinutia_t
*src
, FvsInt_t length
)
277 FvsFloat_t x
, y
, angle
;
278 FvsMinutiaType_t type
;
280 FvsInt_t i
, j
, looking
;
285 for (i
= 1; i
< length
; i
++) {
289 angle
= src
[i
].angle
;
295 while ((j
>= 0) && (looking
== 1)) {
296 // sort with respec to x coordinate
298 src
[j
+ 1].angle
= src
[j
].angle
;
299 src
[j
+ 1].x
= src
[j
].x
;
300 src
[j
+ 1].y
= src
[j
].y
;
301 src
[j
+ 1].type
= src
[j
].type
;
303 src
[j
].angle
= angle
;
311 src
[j
+ 1].angle
= angle
;
314 src
[j
+ 1].type
= type
;