sol9x-sagar commited on
Commit
dfd887d
·
1 Parent(s): 5e28f9f

Feature: Added Enhance Finger Print Image

Browse files
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ *.jpg
2
+ *.png
3
+ __pycache__/
4
+ venv/
5
+ .env
.u2net/u2net.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8d10d2f3bb75ae3b6d527c77944fc5e7dcd94b29809d47a739a7a728a912b491
3
+ size 175997641
Dockerfile CHANGED
@@ -4,6 +4,9 @@ FROM python:3.11-slim
4
 
5
  ENV PYTHONUNBUFFERED=1
6
 
 
 
 
7
  # Set the working directory
8
  WORKDIR /code
9
 
@@ -20,11 +23,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
20
  COPY requirements.txt .
21
  RUN pip install --no-cache-dir -r requirements.txt
22
 
 
 
 
23
  # Copy the rest of the application code
24
  COPY . .
25
 
26
- # Create a directory for the model if it doesn't exist (to match your app.py logic)
27
- RUN mkdir -p /code/model
 
28
 
29
  # Expose the port Hugging Face uses
30
  EXPOSE 7860
 
4
 
5
  ENV PYTHONUNBUFFERED=1
6
 
7
+ # rembg to use a local folder
8
+ ENV U2NET_HOME=/code/.u2net
9
+
10
  # Set the working directory
11
  WORKDIR /code
12
 
 
23
  COPY requirements.txt .
24
  RUN pip install --no-cache-dir -r requirements.txt
25
 
26
+ # Create necessary directories and set permissions
27
+ RUN mkdir -p /code/model /code/.u2net && chmod -R 777 /code
28
+
29
  # Copy the rest of the application code
30
  COPY . .
31
 
32
+ # --- PRE-DOWNLOAD MODEL ---
33
+ # This "cooks" the 176MB model into your Docker layer so the Space starts instantly
34
+ RUN python -c "from rembg import new_session; new_session('u2net')"
35
 
36
  # Expose the port Hugging Face uses
37
  EXPOSE 7860
__pycache__/FingerprintImageEnhancer.cpython-311.pyc DELETED
Binary file (16.2 kB)
 
__pycache__/enhancer.cpython-311.pyc DELETED
Binary file (3.73 kB)
 
app.py CHANGED
@@ -6,13 +6,22 @@ start_import = time.time()
6
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # Hide everything but errors
7
  os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # Force CPU mode immediately
8
 
9
- from flask import Flask, request, jsonify
 
 
10
  import cv2
11
  import numpy as np
12
  import tensorflow as tf
13
  from tensorflow.keras.models import load_model
14
  from os.path import join, dirname
15
 
 
 
 
 
 
 
 
16
  # Import your custom enhancement functions
17
  # Ensure 'enhancer.py' is in the same directory
18
  try:
@@ -33,18 +42,24 @@ MODEL_PATH = join(DIRNAME, 'model', '12_120_fp160.h5')
33
  # Global model variable
34
  model = None
35
 
 
 
 
 
 
36
  def load_and_warmup_model():
37
  global model
 
38
  t_start = time.time()
39
  try:
40
  print(f"Loading model from: {MODEL_PATH}")
41
- model = load_model(MODEL_PATH, compile=False)
42
 
43
  # Warm-up: Run a dummy inference so the first user request isn't slow
44
  print("Warming up model...")
45
  dummy_input = np.zeros((1, 160, 160, 1), dtype=np.float32)
46
  # Use predict_on_batch for faster single-sample inference
47
- model.predict_on_batch([dummy_input, dummy_input])
48
 
49
  print(f"Model loaded and warmed up in: {time.time() - t_start:.2f}s")
50
  except Exception as e:
@@ -53,6 +68,23 @@ def load_and_warmup_model():
53
  # Load model immediately on startup
54
  load_and_warmup_model()
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  def preprocess_fingerprint(image_bytes, image_type):
57
  """
58
  image_type: 'contactless' or 'contactbased'
@@ -156,6 +188,55 @@ def compare_fingerprints():
156
  }
157
  })
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  if __name__ == '__main__':
160
  # Threaded=False is sometimes safer for TF, but Gunicorn handles the workers in prod.
161
  app.run(host='0.0.0.0', port=5000, debug=True)
 
6
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # Hide everything but errors
7
  os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # Force CPU mode immediately
8
 
9
+
10
+
11
+ from flask import Flask, request, jsonify, Response
12
  import cv2
13
  import numpy as np
14
  import tensorflow as tf
15
  from tensorflow.keras.models import load_model
16
  from os.path import join, dirname
17
 
18
+
19
+ from rembg import remove, new_session # <--- Added rembg
20
+ from PIL import Image
21
+
22
+
23
+ # Set model path for rembg (helpful for Docker/HuggingFace)
24
+ os.environ['U2NET_HOME'] = join(dirname(__file__), '.u2net')
25
  # Import your custom enhancement functions
26
  # Ensure 'enhancer.py' is in the same directory
27
  try:
 
42
  # Global model variable
43
  model = None
44
 
45
+ # --- Global Sessions ---
46
+ # Load rembg session once to avoid reload overhead on every request
47
+ rembg_session = new_session("u2net")
48
+ siamese_model = None
49
+
50
  def load_and_warmup_model():
51
  global model
52
+ MODEL_PATH = join(dirname(__file__), 'model', '12_120_fp160.h5')
53
  t_start = time.time()
54
  try:
55
  print(f"Loading model from: {MODEL_PATH}")
56
+ siamese_model = load_model(MODEL_PATH, compile=False)
57
 
58
  # Warm-up: Run a dummy inference so the first user request isn't slow
59
  print("Warming up model...")
60
  dummy_input = np.zeros((1, 160, 160, 1), dtype=np.float32)
61
  # Use predict_on_batch for faster single-sample inference
62
+ siamese_model.predict_on_batch([dummy_input, dummy_input])
63
 
64
  print(f"Model loaded and warmed up in: {time.time() - t_start:.2f}s")
65
  except Exception as e:
 
68
  # Load model immediately on startup
69
  load_and_warmup_model()
70
 
71
+ def remove_bg_from_cv2(cv2_img):
72
+ """
73
+ Converts CV2 image to PIL, removes background,
74
+ and returns back to CV2 (BGR).
75
+ """
76
+ # Convert BGR to RGB for PIL
77
+ img_rgb = cv2.cvtColor(cv2_img, cv2.COLOR_BGR2RGB)
78
+ pil_img = Image.fromarray(img_rgb)
79
+
80
+ # Remove background
81
+ output_pil = remove(pil_img, session=rembg_session)
82
+
83
+ # Convert back to CV2 (and handle transparency)
84
+ # Note: rembg returns RGBA. We convert to BGR for your enhancer.
85
+ output_cv2 = cv2.cvtColor(np.array(output_pil), cv2.COLOR_RGBA2BGR)
86
+ return output_cv2
87
+
88
  def preprocess_fingerprint(image_bytes, image_type):
89
  """
90
  image_type: 'contactless' or 'contactbased'
 
188
  }
189
  })
190
 
191
+ @app.route('/enhance', methods=['POST'])
192
+ def enhance_image_api():
193
+ """
194
+ API Endpoint: /enhance
195
+ Method: POST
196
+ Form-Data: 'image' (file)
197
+ Returns: JPEG image bytes of the enhanced fingerprint
198
+ """
199
+ # 1. Validation
200
+ if 'image' not in request.files:
201
+ return jsonify({"error": "No image file provided. Use key 'image'."}), 400
202
+
203
+ file = request.files['image']
204
+
205
+ if file.filename == '':
206
+ return jsonify({"error": "No selected file"}), 400
207
+
208
+ try:
209
+ # 2. Decode Image
210
+ file_bytes = np.frombuffer(file.read(), np.uint8)
211
+ img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
212
+
213
+ if img is None:
214
+ return jsonify({"error": "Failed to decode image"}), 400
215
+
216
+ # 1. Background Removal
217
+ no_bg = remove_bg_from_cv2(img)
218
+
219
+ # 3. Apply Enhancement Pipeline (Contactless Logic: Basic -> Advanced)
220
+ # Note: basicEnhancing handles grayscale conversion internally if needed
221
+ step1 = basicEnhancing(no_bg)
222
+
223
+ # advancedEnhancing expects the output from basicEnhancing
224
+ final_enhanced = advancedEnhancing(step1)
225
+
226
+ # 4. Encode Result to JPEG
227
+ # Using High Quality (95) to preserve ridge details
228
+ success, encoded_image = cv2.imencode('.jpg', final_enhanced, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
229
+
230
+ if not success:
231
+ return jsonify({"error": "Failed to encode resulting image"}), 500
232
+
233
+ # 5. Return Image Response
234
+ return Response(encoded_image.tobytes(), mimetype='image/jpeg')
235
+
236
+ except Exception as e:
237
+ print(f"Enhancement Error: {e}")
238
+ return jsonify({"error": str(e)}), 500
239
+
240
  if __name__ == '__main__':
241
  # Threaded=False is sometimes safer for TF, but Gunicorn handles the workers in prod.
242
  app.run(host='0.0.0.0', port=5000, debug=True)
enhancer.py CHANGED
@@ -32,7 +32,7 @@ def advancedEnhancing(img):
32
 
33
  if __name__ == '__main__':
34
  # --- Execution Logic ---
35
- image_path = r"C:\Users\SAGAR KESHAVE\Downloads\fore_tip.jpeg"
36
  # image_path = r"C:\SagarKV\sol9x\geekykant\contactless_2d_fingerprint_images\first_session\p247\p1.bmp"
37
  # image_path = r"C:\SagarKV\sol9x\geekykant\contact-based_fingerprints\second_session\13_3.jpg"
38
  original = cv2.imread(image_path)
@@ -69,8 +69,3 @@ if __name__ == '__main__':
69
 
70
  print(f"Comparison strip saved successfully as: {os.path.abspath(output_path)}")
71
 
72
-
73
-
74
-
75
-
76
-
 
32
 
33
  if __name__ == '__main__':
34
  # --- Execution Logic ---
35
+ image_path = r"C:\SagarKV\sol9x\geekykant\contact-contactless-fingerprint\website\app\contactless_to_contactbased_fp_matching\finger_no_bg.png"
36
  # image_path = r"C:\SagarKV\sol9x\geekykant\contactless_2d_fingerprint_images\first_session\p247\p1.bmp"
37
  # image_path = r"C:\SagarKV\sol9x\geekykant\contact-based_fingerprints\second_session\13_3.jpg"
38
  original = cv2.imread(image_path)
 
69
 
70
  print(f"Comparison strip saved successfully as: {os.path.abspath(output_path)}")
71
 
 
 
 
 
 
requirements.txt CHANGED
@@ -3,11 +3,13 @@ albucore==0.0.24
3
  albumentations==2.0.8
4
  annotated-types==0.7.0
5
  astunparse==1.6.3
 
6
  blinker==1.9.0
7
  certifi==2026.1.4
8
  charset-normalizer==3.4.4
9
  click==8.3.1
10
  colorama==0.4.6
 
11
  fingerprint-feature-extractor==0.0.10
12
  fingerprint_enhancer==0.0.14
13
  Flask==3.1.2
@@ -18,40 +20,55 @@ google-pasta==0.2.0
18
  grpcio==1.76.0
19
  gunicorn==24.0.0
20
  h5py==3.15.1
 
21
  idna==3.11
22
  ImageIO==2.37.2
23
  itsdangerous==2.2.0
24
  Jinja2==3.1.6
25
  jsonpickle==4.1.1
 
 
26
  keras==3.13.1
27
  lazy_loader==0.4
28
  libclang==18.1.1
 
29
  Markdown==3.10.1
30
  markdown-it-py==4.0.0
31
  MarkupSafe==3.0.3
32
  mdurl==0.1.2
33
  ml_dtypes==0.5.4
 
34
  namex==0.1.0
35
  networkx==3.6.1
36
- numpy==2.4.1
 
 
37
  opencv-python==4.13.0.90
38
  opencv-python-headless==4.13.0.90
39
  opt_einsum==3.4.0
40
  optree==0.18.0
41
  packaging==26.0
42
  pillow==12.1.0
 
 
43
  protobuf==6.33.4
44
  pydantic==2.12.5
45
  pydantic_core==2.41.5
46
  Pygments==2.19.2
 
 
47
  PyYAML==6.0.3
 
 
48
  requests==2.32.5
49
  rich==14.2.0
 
50
  scikit-image==0.26.0
51
  scipy==1.17.0
52
  simsimd==6.5.12
53
  six==1.17.0
54
  stringzilla==4.6.0
 
55
  tensorboard==2.20.0
56
  tensorboard-data-server==0.7.2
57
  tensorflow==2.20.0
 
3
  albumentations==2.0.8
4
  annotated-types==0.7.0
5
  astunparse==1.6.3
6
+ attrs==25.4.0
7
  blinker==1.9.0
8
  certifi==2026.1.4
9
  charset-normalizer==3.4.4
10
  click==8.3.1
11
  colorama==0.4.6
12
+ coloredlogs==15.0.1
13
  fingerprint-feature-extractor==0.0.10
14
  fingerprint_enhancer==0.0.14
15
  Flask==3.1.2
 
20
  grpcio==1.76.0
21
  gunicorn==24.0.0
22
  h5py==3.15.1
23
+ humanfriendly==10.0
24
  idna==3.11
25
  ImageIO==2.37.2
26
  itsdangerous==2.2.0
27
  Jinja2==3.1.6
28
  jsonpickle==4.1.1
29
+ jsonschema==4.26.0
30
+ jsonschema-specifications==2025.9.1
31
  keras==3.13.1
32
  lazy_loader==0.4
33
  libclang==18.1.1
34
+ llvmlite==0.46.0
35
  Markdown==3.10.1
36
  markdown-it-py==4.0.0
37
  MarkupSafe==3.0.3
38
  mdurl==0.1.2
39
  ml_dtypes==0.5.4
40
+ mpmath==1.3.0
41
  namex==0.1.0
42
  networkx==3.6.1
43
+ numba==0.63.1
44
+ numpy==2.3.5
45
+ onnxruntime==1.23.2
46
  opencv-python==4.13.0.90
47
  opencv-python-headless==4.13.0.90
48
  opt_einsum==3.4.0
49
  optree==0.18.0
50
  packaging==26.0
51
  pillow==12.1.0
52
+ platformdirs==4.5.1
53
+ pooch==1.8.2
54
  protobuf==6.33.4
55
  pydantic==2.12.5
56
  pydantic_core==2.41.5
57
  Pygments==2.19.2
58
+ PyMatting==1.1.15
59
+ pyreadline3==3.5.4
60
  PyYAML==6.0.3
61
+ referencing==0.37.0
62
+ rembg==2.0.72
63
  requests==2.32.5
64
  rich==14.2.0
65
+ rpds-py==0.30.0
66
  scikit-image==0.26.0
67
  scipy==1.17.0
68
  simsimd==6.5.12
69
  six==1.17.0
70
  stringzilla==4.6.0
71
+ sympy==1.14.0
72
  tensorboard==2.20.0
73
  tensorboard-data-server==0.7.2
74
  tensorflow==2.20.0