axvg commited on
Commit
373a8cf
·
verified ·
1 Parent(s): 48168cb
Files changed (6) hide show
  1. .gitattributes +1 -35
  2. Dockerfile +12 -0
  3. app.py +166 -0
  4. matrizMM.txt +10 -0
  5. requirements.txt +6 -0
  6. somhuella.pkl +3 -0
.gitattributes CHANGED
@@ -1,35 +1 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ somhuella.pkl filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12.7
2
+ WORKDIR /code
3
+
4
+ COPY ./requirements.txt /code/requirements.txt
5
+ RUN pip install --no-cache-dir -r /code/requirements.txt
6
+ RUN pip install fastapi uvicorn
7
+
8
+ COPY . .
9
+
10
+ RUN chmod -R 777 /code
11
+
12
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from PIL import Image
3
+ import numpy as np
4
+ from io import BytesIO
5
+ import math
6
+ import pickle
7
+ import os
8
+
9
+ app = FastAPI(title="Fingerprint detection API")
10
+
11
+ som_model = None
12
+ classification_matrix = None
13
+
14
+ def sobel(I):
15
+ m, n = I.shape
16
+ Gx = np.zeros([m-2, n-2], np.float32)
17
+ Gy = np.zeros([m-2, n-2], np.float32)
18
+ gx = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
19
+ gy = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]
20
+
21
+ for j in range(1, m-2):
22
+ for i in range(1, n-2):
23
+ Gx[j-1, i-1] = sum(sum(I[j-1:j+2, i-1:i+2] * gx))
24
+ Gy[j-1, i-1] = sum(sum(I[j-1:j+2, i-1:i+2] * gy))
25
+
26
+ return Gx, Gy
27
+
28
+ def medfilt2(G, d=3):
29
+ m, n = G.shape
30
+ temp = np.zeros([m+2*(d//2), n+2*(d//2)], np.float32)
31
+ salida = np.zeros([m, n], np.float32)
32
+ temp[1:m+1, 1:n+1] = G
33
+
34
+ for i in range(1, m):
35
+ for j in range(1, n):
36
+ A = np.asarray(temp[i-1:i+2, j-1:j+2]).reshape(-1)
37
+ salida[i-1, j-1] = np.sort(A)[d+1]
38
+
39
+ return salida
40
+
41
+ def orientacion(patron, w):
42
+ Gx, Gy = sobel(patron)
43
+ Gx = medfilt2(Gx)
44
+ Gy = medfilt2(Gy)
45
+ m, n = Gx.shape
46
+ mOrientaciones = np.zeros([m//w, n//w], np.float32)
47
+
48
+ for i in range(m//w):
49
+ for j in range(n//w):
50
+ YY = sum(sum(2*Gx[i*w:(i+1)*w, j*w:(j+1)*w]*Gy[i*w:(i+1)*w, j*w:(j+1)*w]))
51
+ XX = sum(sum(Gx[i*w:(i+1)*w, j*w:(j+1)*w]**2-Gy[i*w:(i+1)*w, j*w:(j+1)*w]**2))
52
+ mOrientaciones[i, j] = (0.5*math.atan2(YY, XX) + math.pi/2.0)*(180.0/math.pi)
53
+
54
+ return mOrientaciones
55
+
56
+ def representativo(image_array):
57
+ if isinstance(image_array, np.ndarray):
58
+ if len(image_array.shape) == 3:
59
+ image_array = np.mean(image_array, axis=2)
60
+ im = Image.fromarray(image_array.astype(np.uint8))
61
+ else:
62
+ im = image_array
63
+
64
+ im = im.resize((256, 256))
65
+ m, n = im.size
66
+ imarray = np.array(im, np.float32)
67
+ patron = imarray[1:m-1, 1:n-1]
68
+ EE = orientacion(patron, 14)
69
+
70
+ return np.asarray(EE).reshape(-1)
71
+
72
+ def is_valid_fingerprint_features(features):
73
+ if features is None or len(features) != 324:
74
+ return False
75
+
76
+ if np.any(np.isnan(features)) or np.any(np.isinf(features)):
77
+ return False
78
+
79
+ if np.min(features) < 0 or np.max(features) > 180:
80
+ return False
81
+
82
+ orientation_variance = np.var(features)
83
+ if orientation_variance < 100:
84
+ return False
85
+
86
+ bins = np.histogram(features, bins=18, range=(0, 180))[0]
87
+ non_empty_bins = np.sum(bins > 0)
88
+
89
+ if non_empty_bins < 6:
90
+ return False
91
+
92
+ return True
93
+
94
+ def load_trained_model():
95
+ global som_model, classification_matrix
96
+
97
+ try:
98
+ if os.path.exists('somhuella.pkl'):
99
+ with open('somhuella.pkl', 'rb') as f:
100
+ som_model = pickle.load(f)
101
+ print("OK model")
102
+ else:
103
+ print("cargar somhuella.pkl")
104
+ return False
105
+
106
+ if os.path.exists('matrizMM.txt'):
107
+ classification_matrix = np.loadtxt('matrizMM.txt')
108
+ print("OK matrix")
109
+ else:
110
+ print("load matrix")
111
+ return False
112
+
113
+ return True
114
+ except Exception as e:
115
+ print(f"error {e}")
116
+ return False
117
+
118
+ def detect_and_classify_fingerprint(features):
119
+ global som_model, classification_matrix
120
+
121
+ if not is_valid_fingerprint_features(features):
122
+ return False, "no fingerprint patterns"
123
+
124
+ if som_model is None or classification_matrix is None:
125
+ return True, "Fingerprint pattern detected"
126
+
127
+ try:
128
+ winner = som_model.winner(features)
129
+
130
+ classification_value = classification_matrix[winner]
131
+ if classification_value == -1:
132
+ return False, "no pattern"
133
+
134
+ class_names = {
135
+ 0: "LEFT_LOOP",
136
+ 1: "RIGHT_LOOP",
137
+ 2: "WHORL",
138
+ 3: "ARCO"
139
+ }
140
+
141
+ class_name = class_names.get(int(classification_value), "UNKNOWN")
142
+
143
+ return True, f"{class_name} fingerprint detected (class {int(classification_value)})"
144
+
145
+ except Exception as e:
146
+ print(f"Error in SOM class: {e}")
147
+ return True, "Fingerprint pattern detected (classification error)"
148
+
149
+ load_trained_model()
150
+
151
+ @app.post("/detect_fingerprint/")
152
+ async def detect_fingerprint(file: UploadFile = File(...)):
153
+ try:
154
+ contents = await file.read()
155
+ image = Image.open(BytesIO(contents))
156
+ image_array = np.array(image)
157
+ features = representativo(image_array)
158
+ is_fingerprint, details = detect_and_classify_fingerprint(features)
159
+
160
+ return {
161
+ "fingerprint_detected": is_fingerprint,
162
+ "details": details
163
+ }
164
+
165
+ except Exception as e:
166
+ raise HTTPException(status_code=500, detail=f"error processing image: {str(e)}")
matrizMM.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ -1.000000000000000000e+00 1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 3.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 0.000000000000000000e+00
2
+ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00
3
+ 2.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 0.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00
4
+ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00
5
+ -1.000000000000000000e+00 -1.000000000000000000e+00 1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 0.000000000000000000e+00
6
+ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 2.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00
7
+ 3.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00
8
+ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 3.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00
9
+ -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00
10
+ 3.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 1.000000000000000000e+00 -1.000000000000000000e+00 -1.000000000000000000e+00 2.000000000000000000e+00
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi[standard]
2
+ uvicorn[standard]
3
+ python-multipart
4
+ Pillow
5
+ numpy
6
+ minisom
somhuella.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f4ec5da7c0d90219b85de5d191eeb0356c5d7ffba9310d979872378b48893f90
3
+ size 268015