GOWREESH M G commited on
Commit
9b8b538
·
verified ·
1 Parent(s): 4f82e97

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -43
app.py CHANGED
@@ -28,19 +28,14 @@ MODEL = None
28
  LOAD_ERROR = None # Store the specific reason for failure
29
 
30
  # -------------------- COMPATIBILITY FIX --------------------
31
- # This function dynamically creates a fixed version of any Keras layer
32
- # that ignores the Keras 3 specific arguments (like quantization_config)
33
- # allowing models saved in new versions to load in older environments.
34
  def fix_layer_config(cls):
35
  class FixedLayer(cls):
36
  def __init__(self, *args, **kwargs):
37
- # Remove Keras 3 arguments not supported in Keras 2
38
  kwargs.pop('quantization_config', None)
39
  kwargs.pop('glitch_filter', None)
40
  super().__init__(*args, **kwargs)
41
  return FixedLayer
42
 
43
- # Apply the fix to all layers likely to appear in EfficientNet
44
  CUSTOM_OBJECTS = {
45
  'Dense': fix_layer_config(Dense),
46
  'Dropout': fix_layer_config(Dropout),
@@ -59,61 +54,38 @@ CUSTOM_OBJECTS = {
59
  # -------------------- LOAD MODEL --------------------
60
  def init_model():
61
  global MODEL, LOAD_ERROR
62
- # Reset errors
63
  LOAD_ERROR = None
64
 
65
  if os.path.exists(MODEL_FILE):
66
  print(f"[INIT] Model found: {MODEL_FILE}")
67
  try:
68
- # We pass the custom_objects dictionary to handle the version mismatch
69
  MODEL = load_model(MODEL_FILE, custom_objects=CUSTOM_OBJECTS)
70
  print("[INIT] Model loaded successfully.")
71
  except Exception as e:
72
  print(f"[ERROR] Failed to load model: {e}")
73
- LOAD_ERROR = str(e) # Capture the actual error message
74
  MODEL = None
75
  else:
76
  print(f"[ERROR] Model file '{MODEL_FILE}' NOT FOUND on server.")
77
  MODEL = None
78
 
79
- # -------------------- PREPROCESSING --------------------
80
  def calculate_entropy(img_array):
81
- """
82
- Calculates Shannon Entropy to measure image texture complexity.
83
- Returns a float value (higher = more complex/diseased features).
84
- """
85
  try:
86
- # Ensure image is 0-255 uint8 for histogram calculation
87
  if img_array.dtype != np.uint8:
88
- # If normalized 0-1, scale up. If just float 0-255, cast.
89
- if np.max(img_array) <= 1.0:
90
- calc_img = (img_array * 255).astype(np.uint8)
91
- else:
92
- calc_img = img_array.astype(np.uint8)
93
- else:
94
- calc_img = img_array
95
 
96
- # Convert to grayscale if it's color (Batch dim, H, W, C) or (H, W, C)
97
- if len(calc_img.shape) == 4: # (1, 224, 224, 3)
98
- calc_img = calc_img[0]
99
-
100
  gray = cv2.cvtColor(calc_img, cv2.COLOR_RGB2GRAY)
101
-
102
- # Compute histogram
103
  hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
104
-
105
- # Normalize histogram to get probabilities
106
  hist_norm = hist.ravel() / hist.sum()
107
-
108
- # Filter zero values to avoid log(0) error
109
  hist_norm = hist_norm[hist_norm > 0]
110
-
111
- # Entropy formula: -Sum(p * log2(p))
112
  entropy_val = -np.sum(hist_norm * np.log2(hist_norm))
113
  return float(entropy_val)
114
  except Exception as e:
115
- print(f"Entropy Error: {e}")
116
- return 4.5 # Fallback average value
117
 
118
  def process_single_image(image_path):
119
  try:
@@ -133,7 +105,29 @@ def process_single_image(image_path):
133
 
134
  return np.expand_dims(final.astype(np.float32) / 255.0, axis=0)
135
  except Exception as e:
136
- return str(e) # Return error string instead of None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  # -------------------- ROUTES --------------------
139
  @app.route("/")
@@ -153,12 +147,11 @@ def analyze():
153
  if not os.path.exists(MODEL_FILE):
154
  return jsonify({
155
  "diagnosis": "System Error",
156
- "description": f"Model file '{MODEL_FILE}' not found. Did you upload it?",
157
  "confidence": "0%",
158
  "color": "rose", "icon": "alert-octagon"
159
  })
160
  else:
161
- # Use the captured specific error message
162
  error_msg = LOAD_ERROR if LOAD_ERROR else "Model initialization skipped by server."
163
  return jsonify({
164
  "diagnosis": "Load Error",
@@ -169,8 +162,6 @@ def analyze():
169
 
170
  # 2. Process Image
171
  input_data = process_single_image(temp_path)
172
-
173
- # Check if processing failed (returned an error string)
174
  if isinstance(input_data, str):
175
  return jsonify({
176
  "diagnosis": "OpenCV Error",
@@ -179,8 +170,9 @@ def analyze():
179
  "color": "rose", "icon": "alert-triangle"
180
  })
181
 
182
- # 3. Predict
183
- preds = MODEL.predict(input_data)[0]
 
184
  idx = np.argmax(preds)
185
  label = CLASSES[idx]
186
  conf = preds[idx] * 100
@@ -215,7 +207,6 @@ def analyze():
215
  if os.path.exists(temp_path): os.remove(temp_path)
216
 
217
  # -------------------- INITIALIZE ON IMPORT --------------------
218
- # Crucial Fix: Call init_model() globally so Gunicorn runs it!
219
  init_model()
220
 
221
  if __name__ == "__main__":
 
28
  LOAD_ERROR = None # Store the specific reason for failure
29
 
30
  # -------------------- COMPATIBILITY FIX --------------------
 
 
 
31
  def fix_layer_config(cls):
32
  class FixedLayer(cls):
33
  def __init__(self, *args, **kwargs):
 
34
  kwargs.pop('quantization_config', None)
35
  kwargs.pop('glitch_filter', None)
36
  super().__init__(*args, **kwargs)
37
  return FixedLayer
38
 
 
39
  CUSTOM_OBJECTS = {
40
  'Dense': fix_layer_config(Dense),
41
  'Dropout': fix_layer_config(Dropout),
 
54
  # -------------------- LOAD MODEL --------------------
55
  def init_model():
56
  global MODEL, LOAD_ERROR
 
57
  LOAD_ERROR = None
58
 
59
  if os.path.exists(MODEL_FILE):
60
  print(f"[INIT] Model found: {MODEL_FILE}")
61
  try:
 
62
  MODEL = load_model(MODEL_FILE, custom_objects=CUSTOM_OBJECTS)
63
  print("[INIT] Model loaded successfully.")
64
  except Exception as e:
65
  print(f"[ERROR] Failed to load model: {e}")
66
+ LOAD_ERROR = str(e)
67
  MODEL = None
68
  else:
69
  print(f"[ERROR] Model file '{MODEL_FILE}' NOT FOUND on server.")
70
  MODEL = None
71
 
72
+ # -------------------- PREPROCESSING & TTA --------------------
73
  def calculate_entropy(img_array):
 
 
 
 
74
  try:
 
75
  if img_array.dtype != np.uint8:
76
+ if np.max(img_array) <= 1.0: calc_img = (img_array * 255).astype(np.uint8)
77
+ else: calc_img = img_array.astype(np.uint8)
78
+ else: calc_img = img_array
 
 
 
 
79
 
80
+ if len(calc_img.shape) == 4: calc_img = calc_img[0]
 
 
 
81
  gray = cv2.cvtColor(calc_img, cv2.COLOR_RGB2GRAY)
 
 
82
  hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
 
 
83
  hist_norm = hist.ravel() / hist.sum()
 
 
84
  hist_norm = hist_norm[hist_norm > 0]
 
 
85
  entropy_val = -np.sum(hist_norm * np.log2(hist_norm))
86
  return float(entropy_val)
87
  except Exception as e:
88
+ return 4.5
 
89
 
90
  def process_single_image(image_path):
91
  try:
 
105
 
106
  return np.expand_dims(final.astype(np.float32) / 255.0, axis=0)
107
  except Exception as e:
108
+ return str(e)
109
+
110
+ def predict_with_tta(model, input_batch):
111
+ """
112
+ Test Time Augmentation:
113
+ Predicts on the original image + flipped versions and averages the results.
114
+ """
115
+ img = input_batch[0] # Extract image from batch (224, 224, 3)
116
+
117
+ # Create batch of 3 variants: Original, Horizontal Flip, Vertical Flip
118
+ # Retina images have no "correct" up/down, so vertical flipping is valid logic.
119
+ aug_batch = np.array([
120
+ img,
121
+ np.fliplr(img),
122
+ np.flipud(img)
123
+ ])
124
+
125
+ # Get predictions for all 3 variations
126
+ preds = model.predict(aug_batch)
127
+
128
+ # Average the probabilities across the 3 views
129
+ avg_pred = np.mean(preds, axis=0)
130
+ return avg_pred
131
 
132
  # -------------------- ROUTES --------------------
133
  @app.route("/")
 
147
  if not os.path.exists(MODEL_FILE):
148
  return jsonify({
149
  "diagnosis": "System Error",
150
+ "description": f"Model file '{MODEL_FILE}' not found.",
151
  "confidence": "0%",
152
  "color": "rose", "icon": "alert-octagon"
153
  })
154
  else:
 
155
  error_msg = LOAD_ERROR if LOAD_ERROR else "Model initialization skipped by server."
156
  return jsonify({
157
  "diagnosis": "Load Error",
 
162
 
163
  # 2. Process Image
164
  input_data = process_single_image(temp_path)
 
 
165
  if isinstance(input_data, str):
166
  return jsonify({
167
  "diagnosis": "OpenCV Error",
 
170
  "color": "rose", "icon": "alert-triangle"
171
  })
172
 
173
+ # 3. Predict with TTA (Smart Averaging)
174
+ preds = predict_with_tta(MODEL, input_data)
175
+
176
  idx = np.argmax(preds)
177
  label = CLASSES[idx]
178
  conf = preds[idx] * 100
 
207
  if os.path.exists(temp_path): os.remove(temp_path)
208
 
209
  # -------------------- INITIALIZE ON IMPORT --------------------
 
210
  init_model()
211
 
212
  if __name__ == "__main__":