JanithDeshan24 commited on
Commit
cb746f2
Β·
verified Β·
1 Parent(s): a48819c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -162
app.py CHANGED
@@ -1,162 +1,162 @@
1
- import os
2
- import numpy as np
3
- import tensorflow as tf
4
- from flask import Flask, request, render_template, send_from_directory
5
- from werkzeug.utils import secure_filename
6
- from PIL import UnidentifiedImageError # To catch corrupted image errors
7
-
8
- # --- 1. CONFIGURATION ---
9
- app = Flask(__name__)
10
- UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
11
- app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
12
- os.makedirs(UPLOAD_FOLDER, exist_ok=True)
13
-
14
- # Define paths for the .h5 models
15
- BREED_MODEL_PATH = 'dog_breed_project_model.h5' # <-- UPDATED FILENAME
16
- GATEKEEPER_MODEL_PATH = 'gatekeeper_model.h5' # <-- UPDATED FILENAME
17
- CLASS_NAMES_PATH = 'class_names.txt'
18
- IMG_SIZE = 224
19
-
20
- # --- 2. LOAD MODELS AND CLASS NAMES (ONCE AT STARTUP) ---
21
- print("--- Loading models and class names... ---")
22
- try:
23
- # Load the expert model for breed classification
24
- breed_model = tf.keras.models.load_model(BREED_MODEL_PATH)
25
- print("βœ… Dog Breed (Expert) model loaded.")
26
-
27
- # Load the gatekeeper model for dog vs. not-dog classification
28
- gatekeeper_model = tf.keras.models.load_model(GATEKEEPER_MODEL_PATH)
29
- print("βœ… Gatekeeper (Dog vs. Not-Dog) model loaded.")
30
-
31
- # Load class names
32
- with open(CLASS_NAMES_PATH, 'r') as f:
33
- class_names = [line.strip() for line in f.readlines()]
34
- print(f"βœ… Class names loaded. Found {len(class_names)} classes.")
35
-
36
- except Exception as e:
37
- print(f"❌ Error loading models: {e}")
38
- # Define dummy models so the app doesn't crash on startup
39
- breed_model = None
40
- gatekeeper_model = None
41
-
42
- print("--- Setup complete ---")
43
-
44
-
45
- # --- 3. IMAGE PREPROCESSING FUNCTION (CONSISTENT WITH TRAINING) ---
46
- def preprocess_uploaded_image(filepath, img_size):
47
- """
48
- Loads, decodes, and preprocesses an uploaded image for both models.
49
- This function handles different file types, grayscale images, and aspect ratios.
50
- """
51
- try:
52
- # Read the file and decode it as a 3-channel (RGB) image
53
- img = tf.io.read_file(filepath)
54
- img = tf.image.decode_image(img, channels=3, expand_animations=False)
55
-
56
- # Pad to a square aspect ratio without distortion
57
- img = tf.image.resize_with_pad(img, img_size, img_size)
58
-
59
- # Expand dimensions to create a batch of 1
60
- img_batch = tf.expand_dims(img, 0)
61
-
62
- # Preprocess for each model's specific requirements
63
- gatekeeper_input = tf.keras.applications.mobilenet_v2.preprocess_input(tf.identity(img_batch))
64
- breed_model_input = tf.keras.applications.resnet_v2.preprocess_input(tf.identity(img_batch))
65
-
66
- return gatekeeper_input, breed_model_input
67
-
68
- except (UnidentifiedImageError, tf.errors.InvalidArgumentError):
69
- # Handle cases where the file is not a valid image
70
- return None, None
71
- except Exception as e:
72
- print(f"An unexpected error occurred during preprocessing: {e}")
73
- return None, None
74
-
75
-
76
- # --- 4. FLASK ROUTES ---
77
- @app.route('/', methods=['GET', 'POST'])
78
- def index():
79
- if request.method == 'POST':
80
- if not all([breed_model, gatekeeper_model]):
81
- return render_template('index.html', error="Models are not loaded. Please check the server logs.")
82
-
83
- if 'file' not in request.files:
84
- return render_template('index.html', error="No file part in the request.")
85
-
86
- file = request.files['file']
87
- if file.filename == '':
88
- return render_template('index.html', error="No file selected.")
89
-
90
- if file:
91
- filename = secure_filename(file.filename)
92
- filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
93
- file.save(filepath)
94
-
95
- # --- PREDICTION PIPELINE ---
96
- gatekeeper_img, breed_img = preprocess_uploaded_image(filepath, IMG_SIZE)
97
-
98
- if gatekeeper_img is None:
99
- return render_template('index.html', error="Invalid or corrupted image file. Please try another.")
100
-
101
- # Step 1: Use the Gatekeeper to check if the image is a dog
102
- gatekeeper_pred = gatekeeper_model.predict(gatekeeper_img)[0][0]
103
-
104
- if gatekeeper_pred > 0.5:
105
- # -----------------------------------------------------------------
106
- # START: UPGRADED LOGIC WITH TEST-TIME AUGMENTATION (TTA)
107
- # -----------------------------------------------------------------
108
-
109
- # Create 4 augmented versions of the image (0, 90, 180, 270 degrees)
110
- images_to_predict = [
111
- breed_img,
112
- tf.image.rot90(breed_img, k=1), # 90 degrees
113
- tf.image.rot90(breed_img, k=2), # 180 degrees (upside down)
114
- tf.image.rot90(breed_img, k=3) # 270 degrees
115
- ]
116
-
117
- # Stack the images into a single batch
118
- tta_batch = tf.concat(images_to_predict, axis=0)
119
-
120
- # Get predictions for all 4 images in one go
121
- batch_predictions = breed_model.predict(tta_batch)
122
-
123
- # Average the predictions to get the final, robust result
124
- breed_predictions = tf.reduce_mean(batch_predictions, axis=0)
125
-
126
- # -----------------------------------------------------------------
127
- # END: UPGRADED LOGIC WITH TEST-TIME AUGMENTATION (TTA)
128
- # -----------------------------------------------------------------
129
-
130
- # Get top 3 predictions from the averaged result
131
- top_k_values, top_k_indices = tf.math.top_k(breed_predictions, k=3)
132
-
133
- top_breeds = []
134
- for i in range(3):
135
- breed_name = class_names[top_k_indices[i]]
136
- confidence = top_k_values[i] * 100
137
- top_breeds.append({"name": breed_name.replace("_", " ").title(), "confidence": f"{confidence:.2f}%"})
138
-
139
- return render_template('index.html',
140
- is_dog=True,
141
- predictions=top_breeds,
142
- uploaded_image=filename)
143
- else:
144
- # If it's not a dog, return a clear message
145
- not_dog_confidence = (1 - gatekeeper_pred) * 100
146
- return render_template('index.html',
147
- is_dog=False,
148
- prediction_text=f"This doesn't look like a dog.",
149
- confidence_text=f"({not_dog_confidence:.2f}% sure it's not a dog)",
150
- uploaded_image=filename)
151
-
152
- return render_template('index.html')
153
-
154
-
155
- @app.route('/uploads/<filename>')
156
- def uploaded_file(filename):
157
- """Serves the uploaded file to be displayed on the webpage."""
158
- return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
159
-
160
-
161
- if __name__ == '__main__':
162
- app.run(debug=True)
 
1
+ import os
2
+ import numpy as np
3
+ import tensorflow as tf
4
+ from flask import Flask, request, render_template, send_from_directory
5
+ from werkzeug.utils import secure_filename
6
+ from PIL import UnidentifiedImageError # To catch corrupted image errors
7
+
8
+ # --- 1. CONFIGURATION ---
9
+ app = Flask(__name__)
10
+ UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
11
+ app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
12
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
13
+
14
+ # Define paths for the .h5 models
15
+ BREED_MODEL_PATH = 'dog_breed_project_model.h5' # <-- UPDATED FILENAME
16
+ GATEKEEPER_MODEL_PATH = 'gatekeeper_model.h5' # <-- UPDATED FILENAME
17
+ CLASS_NAMES_PATH = 'class_names.txt'
18
+ IMG_SIZE = 224
19
+
20
+ # --- 2. LOAD MODELS AND CLASS NAMES (ONCE AT STARTUP) ---
21
+ print("--- Loading models and class names... ---")
22
+ try:
23
+ # Load the expert model for breed classification
24
+ breed_model = tf.keras.models.load_model(BREED_MODEL_PATH)
25
+ print("βœ… Dog Breed (Expert) model loaded.")
26
+
27
+ # Load the gatekeeper model for dog vs. not-dog classification
28
+ gatekeeper_model = tf.keras.models.load_model(GATEKEEPER_MODEL_PATH)
29
+ print("βœ… Gatekeeper (Dog vs. Not-Dog) model loaded.")
30
+
31
+ # Load class names
32
+ with open(CLASS_NAMES_PATH, 'r') as f:
33
+ class_names = [line.strip() for line in f.readlines()]
34
+ print(f"βœ… Class names loaded. Found {len(class_names)} classes.")
35
+
36
+ except Exception as e:
37
+ print(f"❌ Error loading models: {e}")
38
+ # Define dummy models so the app doesn't crash on startup
39
+ breed_model = None
40
+ gatekeeper_model = None
41
+
42
+ print("--- Setup complete ---")
43
+
44
+
45
+ # --- 3. IMAGE PREPROCESSING FUNCTION (CONSISTENT WITH TRAINING) ---
46
+ def preprocess_uploaded_image(filepath, img_size):
47
+ """
48
+ Loads, decodes, and preprocesses an uploaded image for both models.
49
+ This function handles different file types, grayscale images, and aspect ratios.
50
+ """
51
+ try:
52
+ # Read the file and decode it as a 3-channel (RGB) image
53
+ img = tf.io.read_file(filepath)
54
+ img = tf.image.decode_image(img, channels=3, expand_animations=False)
55
+
56
+ # Pad to a square aspect ratio without distortion
57
+ img = tf.image.resize_with_pad(img, img_size, img_size)
58
+
59
+ # Expand dimensions to create a batch of 1
60
+ img_batch = tf.expand_dims(img, 0)
61
+
62
+ # Preprocess for each model's specific requirements
63
+ gatekeeper_input = tf.keras.applications.mobilenet_v2.preprocess_input(tf.identity(img_batch))
64
+ breed_model_input = tf.keras.applications.resnet_v2.preprocess_input(tf.identity(img_batch))
65
+
66
+ return gatekeeper_input, breed_model_input
67
+
68
+ except (UnidentifiedImageError, tf.errors.InvalidArgumentError):
69
+ # Handle cases where the file is not a valid image
70
+ return None, None
71
+ except Exception as e:
72
+ print(f"An unexpected error occurred during preprocessing: {e}")
73
+ return None, None
74
+
75
+
76
+ # --- 4. FLASK ROUTES ---
77
+ @app.route('/', methods=['GET', 'POST'])
78
+ def index():
79
+ if request.method == 'POST':
80
+ if not all([breed_model, gatekeeper_model]):
81
+ return render_template('index.html', error="Models are not loaded. Please check the server logs.")
82
+
83
+ if 'file' not in request.files:
84
+ return render_template('index.html', error="No file part in the request.")
85
+
86
+ file = request.files['file']
87
+ if file.filename == '':
88
+ return render_template('index.html', error="No file selected.")
89
+
90
+ if file:
91
+ filename = secure_filename(file.filename)
92
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
93
+ file.save(filepath)
94
+
95
+ # --- PREDICTION PIPELINE ---
96
+ gatekeeper_img, breed_img = preprocess_uploaded_image(filepath, IMG_SIZE)
97
+
98
+ if gatekeeper_img is None:
99
+ return render_template('index.html', error="Invalid or corrupted image file. Please try another.")
100
+
101
+ # Step 1: Use the Gatekeeper to check if the image is a dog
102
+ gatekeeper_pred = gatekeeper_model.predict(gatekeeper_img)[0][0]
103
+
104
+ if gatekeeper_pred > 0.5:
105
+ # -----------------------------------------------------------------
106
+ # START: UPGRADED LOGIC WITH TEST-TIME AUGMENTATION (TTA)
107
+ # -----------------------------------------------------------------
108
+
109
+ # Create 4 augmented versions of the image (0, 90, 180, 270 degrees)
110
+ images_to_predict = [
111
+ breed_img,
112
+ tf.image.rot90(breed_img, k=1), # 90 degrees
113
+ tf.image.rot90(breed_img, k=2), # 180 degrees (upside down)
114
+ tf.image.rot90(breed_img, k=3) # 270 degrees
115
+ ]
116
+
117
+ # Stack the images into a single batch
118
+ tta_batch = tf.concat(images_to_predict, axis=0)
119
+
120
+ # Get predictions for all 4 images in one go
121
+ batch_predictions = breed_model.predict(tta_batch)
122
+
123
+ # Average the predictions to get the final, robust result
124
+ breed_predictions = tf.reduce_mean(batch_predictions, axis=0)
125
+
126
+ # -----------------------------------------------------------------
127
+ # END: UPGRADED LOGIC WITH TEST-TIME AUGMENTATION (TTA)
128
+ # -----------------------------------------------------------------
129
+
130
+ # Get top 3 predictions from the averaged result
131
+ top_k_values, top_k_indices = tf.math.top_k(breed_predictions, k=3)
132
+
133
+ top_breeds = []
134
+ for i in range(3):
135
+ breed_name = class_names[top_k_indices[i]]
136
+ confidence = top_k_values[i] * 100
137
+ top_breeds.append({"name": breed_name.replace("_", " ").title(), "confidence": f"{confidence:.2f}%"})
138
+
139
+ return render_template('index.html',
140
+ is_dog=True,
141
+ predictions=top_breeds,
142
+ uploaded_image=filename)
143
+ else:
144
+ # If it's not a dog, return a clear message
145
+ not_dog_confidence = (1 - gatekeeper_pred) * 100
146
+ return render_template('index.html',
147
+ is_dog=False,
148
+ prediction_text=f"This doesn't look like a dog.",
149
+ confidence_text=f"({not_dog_confidence:.2f}% sure it's not a dog)",
150
+ uploaded_image=filename)
151
+
152
+ return render_template('index.html')
153
+
154
+
155
+ @app.route('/uploads/<filename>')
156
+ def uploaded_file(filename):
157
+ """Serves the uploaded file to be displayed on the webpage."""
158
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
159
+
160
+
161
+ if __name__ == '__main__':
162
+ app.run(host="0.0.0.0", port=7860)