File size: 12,972 Bytes
b3ccc23
 
bea7953
b3ccc23
5808f01
b3ccc23
 
c859c19
 
 
b3ccc23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59f7c59
 
 
 
 
 
b3ccc23
 
 
 
 
 
 
 
 
 
 
 
 
 
45163f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32cec0d
45163f5
 
 
 
c859c19
9ae50c9
b408297
 
 
 
 
 
56a66d5
b408297
9ae50c9
c859c19
 
b408297
c859c19
 
b408297
c859c19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b3ccc23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a8bc1c1
1b06e57
 
a8bc1c1
b3ccc23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45163f5
b3ccc23
 
 
9ae50c9
 
 
 
b3ccc23
c859c19
6e37c7e
c859c19
b3ccc23
 
 
a8bc1c1
003a05b
b3ccc23
 
 
 
 
 
 
 
c859c19
 
a8bc1c1
b3ccc23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c859c19
 
003a05b
b3ccc23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2698bb4
 
 
 
a8bc1c1
b3ccc23
a8bc1c1
b3ccc23
 
 
 
 
 
 
 
 
 
003a05b
a8bc1c1
b3ccc23
 
 
 
 
 
 
 
 
 
 
 
 
45163f5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
import gradio as gr
import pandas as pd
import numpy as np 
import tensorflow as tf
import mlxtend
import joblib
import cv2
import matplotlib.pyplot as plt
import seaborn as sns
import tempfile
from sklearn.preprocessing import LabelEncoder
from tensorflow.keras.models import save_model, load_model
from PIL import Image
from gradio import components as gr_components

# Load the dataset and get the column names
dataset = pd.read_csv('Covid_Dataset.csv')
columns_to_drop = ['Wearing Masks', 'Sanitization from Market']
dataset = dataset.drop(columns_to_drop, axis=1)
column_names = dataset.columns.tolist()

# Load the text-based model
model_logreg = joblib.load('logreg_model.h5')
model_rf_classifier = joblib.load('rf_classifier_model.h5')
model_dt_classifier = joblib.load('dt_classifier_model.h5')
model_knn_classifier = joblib.load('knn_classifier_model.h5')
model_svm_classifier = joblib.load('svm_classifier_model.h5')
model_ann_classifier = joblib.load('ann_model.h5')
voting_classifier = joblib.load('voting_classifier_model.h5')
stacking_classifier = joblib.load('stacking_classifier_model.h5')

# CustomScaleLayer definition
class CustomScaleLayer(tf.keras.layers.Layer):
    def __init__(self):
        super(CustomScaleLayer, self).__init__()

    def call(self, inputs):        
        return inputs * 2

# Register the custom layer within the custom object scope
tf.keras.utils.get_custom_objects()['CustomScaleLayer'] = CustomScaleLayer

# Load the image-based models with the custom object scope
inception_model = tf.keras.models.load_model('xray_inception_model.h5', compile=False)
resnet_model = tf.keras.models.load_model('xray_resnet_model.h5', compile=False)
densenet_model = tf.keras.models.load_model('xray_densenet_model.h5', compile=False)
vgg19_model = tf.keras.models.load_model('xray_vgg19_model.h5', compile=False)
efficientnet_model = tf.keras.models.load_model('xray_efficientnet_model.h5', compile=False)
mobilenet_model = tf.keras.models.load_model('xray_mobilenet_model.h5', compile=False)

# Define the ensemble models
ensemble_models = {
    'InceptionResnetV2': inception_model,
    'ResNet50': resnet_model,
    'DenseNet121': densenet_model,
    'VGG19': vgg19_model,
    'EfficientNetV2B3': efficientnet_model,
    'MobileNetV2': mobilenet_model
}

class_labels = ['COVID-19', 'Normal', 'Viral Pneumonia']
class_index_mapping = {i: label for i, label in enumerate(class_labels)}

# Define a dictionary with custom weightage for each symptom
custom_symptom_weightage = {
    "Breathing Problem": 1.0,
    "Fever": 1.0,
    "Dry Cough": 1.0,
    "Sore throat": 1.0,
    "Running Nose": 1.0,
    "Asthma": 1.0,
    "Chronic Lung Disease": 1.0,
    "Headache": 1.0,
    "Heart Disease": 0.7,
    "Diabetes": 1.0,
    "Hyper Tension": 1.0,
    "Fatigue": 0.9,
    "Gastrointestinal": 0.7,
    "Abroad Travel": 0.5,
    "Contact with COVID Patient": 1.0,
    "Attended Large Gathering": 0.5,
    "Visited Public Exposed Places": 0.5,
    "Family Working in Public Exposed Places": 0.5,
}

def show_symptom_weightage(symptoms, weights):
    selected_symptoms = [symptom for symptom, weight in zip(symptoms, weights) if weight > 0]

    # Check if any symptom is selected by the user
    if len(selected_symptoms) == 0:
        # If no symptom is selected, return None to indicate no bar graph should be displayed
        return None

    selected_weights = [weight for weight in weights if weight > 0]
    plt.figure(figsize=(10, 6))
    plt.bar(selected_symptoms, selected_weights)
    plt.xlabel("Symptom")
    plt.ylabel("Weight")
    plt.title("Weightage/Importance of Selected Symptoms")
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()

    # Save the plot as an image and return the file path
    file_path = tempfile.NamedTemporaryFile(suffix=".png").name
    plt.savefig(file_path)
    plt.close()
    return file_path

# Create a heat map to represent image-based model predictions
def show_heat_map(image, prediction_probabilities):
    plt.figure(figsize=(8, 6))
    sns.heatmap(prediction_probabilities, annot=True, cmap="YlGnBu", xticklabels=class_labels, yticklabels=False)
    plt.title("Image-based Model Prediction Heatmap")
    plt.xlabel("Prediction")
    plt.ylabel("Model")
    plt.tight_layout()
    # Save the plot as an image and return the file path
    file_path = tempfile.NamedTemporaryFile(suffix=".png").name
    plt.savefig(file_path)
    plt.close()
    return file_path
    
# Apply the same rescaling as in the model
def rescale_images(img):
    return img / 127.5 - 1

def is_scan_blurry(image):
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    laplacian_var = cv2.Laplacian(gray, cv2.CV_64F).var()
    return laplacian_var < 15
    
# Define a function to preprocess the image
def preprocess_image(image):        
    image = image.copy()  
    image = Image.fromarray(image)  # Convert the array to PIL Image
    image = image.resize((128, 128))         
    image = np.array(image)
    image = rescale_images(image)      
    return image
    
# Define a function to make predictions using the selected models
def predict_covid(*args):    
    symptoms = [False if symptom is None else symptom for symptom in args[:-1]] # Convert None values to False
    image = args[-1]

    if not any(symptoms) and image is None:
        return "COVID-19 Negative", "100%", "COVID-19 Negative", "100%", "No inputs defined", None, None

    if any(symptoms) and image is None:
        return "NA", "NA", "NA", "NA", "Please select the Symptoms and provide the Chest X-Ray Scan", None, None
        
    # Prepare the input data for the text-based model
    label_encoder = LabelEncoder()
    input_data = pd.DataFrame([list(symptoms)], columns=column_names[:-1])
    encoded_input_data = input_data.copy()
    for column in encoded_input_data.columns:
        if encoded_input_data[column].dtype == object:
            encoded_input_data[column] = label_encoder.transform(encoded_input_data[column])

    # Make predictions using the text-based model
    logreg_prediction = int(model_logreg.predict(encoded_input_data)[0])
    rf_prediction = int(model_rf_classifier.predict(encoded_input_data)[0])
    dt_prediction = int(model_dt_classifier.predict(encoded_input_data)[0])
    knn_prediction = int(model_knn_classifier.predict(encoded_input_data)[0])
    svm_prediction = int(model_svm_classifier.predict(encoded_input_data)[0])
    ann_prediction = int(model_ann_classifier.predict(encoded_input_data)[0])
    voting_prediction = int(voting_classifier.predict(encoded_input_data)[0])
    stacking_prediction = int(stacking_classifier.predict(encoded_input_data)[0])

    # Get the probabilities for text-based models
    logreg_prob_positive = model_logreg.predict_proba(encoded_input_data)[0][1]
    rf_prob_positive = model_rf_classifier.predict_proba(encoded_input_data)[0][1]
    dt_prob_positive = model_dt_classifier.predict_proba(encoded_input_data)[0][1]
    knn_prob_positive = model_knn_classifier.predict_proba(encoded_input_data)[0][1]    
    ann_prob_positive = model_ann_classifier.predict_proba(encoded_input_data)[0][1]
    if model_svm_classifier.probability:
        svm_prob_positive = model_svm_classifier.predict_proba(encoded_input_data)[0][1]
    else:
        svm_prob_positive = model_svm_classifier.decision_function(encoded_input_data)[0]


    # Determine the overall prediction from the text-based model
    positive_predictions = sum([logreg_prediction, rf_prediction, dt_prediction,
                                knn_prediction, svm_prediction, ann_prediction])

    text_prediction = "COVID-19 Positive" if positive_predictions >= 4 else "COVID-19 Negative"

    # Determine the overall prediction from the text-based model
    if text_prediction is None:
        text_prediction = "NA"
        text_prob_positive = 0.0
    
    weights = [custom_symptom_weightage[symptom] if symptom in custom_symptom_weightage else 0.0 for symptom in column_names[:-1]]
    probabilities = [logreg_prob_positive, rf_prob_positive, dt_prob_positive,
                     knn_prob_positive, svm_prob_positive, ann_prob_positive]

    # Manually calculate the weighted average
    total_weighted_prob = sum(prob * weight for prob, weight in zip(probabilities, weights))
    total_weight = sum(weights)
    text_prob_positive = (total_weighted_prob / total_weight) * 100 if total_weight != 0 else 0.0

    # Visualize the symptom weightage/importance    
    symptom_weightage_img = show_symptom_weightage(column_names[:-1], weights)    
    
    # Prepare the input data for the image-based model
    image_prediction = None
    confidence = None
    reason = None    
    
    if image is not None:
        is_blurry = is_scan_blurry(image)
        if is_blurry:
            return (
                "Invalid X-Ray Scan",
                "NA",
                "Invalid X-Ray Scan",
                "NA",
                "Your X-Ray scan does not meet the required standards. Please ensure that your scans are not blurry, pixelated, or disfigured",
                None,
                None            
            )
        
        image = preprocess_image(image)

        # Make predictions using the ensemble models
        ensemble_predictions = []
        for model_name, model in ensemble_models.items():
            prediction = model.predict(image[np.newaxis, ...])[0]
            probabilities = prediction / np.sum(prediction)  
            ensemble_predictions.append((prediction, probabilities))
    
        # Calculate the average prediction from the ensemble models
        avg_ensemble_prob = np.mean([probabilities for _, probabilities in ensemble_predictions], axis=0)
        ensemble_prediction = np.argmax(avg_ensemble_prob)
        image_prediction = class_index_mapping[ensemble_prediction]

        # Calculate the confidence level of the prediction
        confidence = np.max(avg_ensemble_prob) * 100

        # Visualize the heatmap
        heatmap_img = show_heat_map(image, [prediction for prediction, _ in ensemble_predictions])

        # Provide reasoning for the prediction
        if ensemble_prediction == 0 and text_prediction == "COVID-19 Positive":
            reason = "Your X-Ray scan and symptoms provide conclusive indications of COVID-19" 
        
        elif text_prediction == "COVID-19 Positive" and ensemble_prediction != 0:
            if text_prob_positive > confidence:                
                reason = "Your symptoms provide conclusive indications of COVID-19"
                
            else:
                reason = "Your X-Ray scan provides no conclusive indications of COVID-19"
        
        elif text_prediction == "COVID-19 Negative" and ensemble_prediction != 0:
                reason = "Your X-Ray scan and symptoms provide no conclusive indications of COVID-19"
        
        elif ensemble_prediction == 0 and text_prediction == "COVID-19 Negative":
            if text_prob_positive > confidence:                
                reason = "Your symptoms provide no conclusive indications of COVID-19"
                
            else:
                reason = "Your X-Ray scan provides conclusive indications of COVID-19" 
            
        else:
            reason = "Your X-Ray scan provides no conclusive indications of COVID-19"
    
    else:
        reason = "Your symptoms provide conclusive indications of your diagnosis"

    # Ensure that confidence and other variables have a valid value
    confidence = 0.0 if confidence is None else confidence
    heatmap_img = "" if heatmap_img is None else heatmap_img
    symptom_weightage_img = "" if symptom_weightage_img is None else symptom_weightage_img    
        
    return text_prediction, f"{text_prob_positive:.2f}%", image_prediction, f"{confidence:.2f}%", reason, symptom_weightage_img, heatmap_img

# Create the input and output components
symptom_components = [gr_components.Checkbox(label=label) for label in column_names[:-1]]
image_component = gr_components.Image()
output_components = [
    gr_components.Label(label="Prediction based on Symptoms"),
    gr_components.Label(label="Symptom Confidence (%)"),
    gr_components.Label(label="Prediction based on X-Ray Scan"),
    gr_components.Label(label="X-Ray Scan Confidence (%)"),
    gr_components.Textbox(label="Final Prediction"),
    gr_components.Image(label="Weightage assigned to Symptoms"),
    gr_components.Image(label="X-Ray Prediction Heatmap")
]

# Create the interface and launch
iface = gr.Interface(
    fn=predict_covid,
    inputs=symptom_components + [image_component],
    outputs=output_components,
    title="COVID-19 Detection", 
    description="Select the symptom(s) from the list and upload the X-Ray image of your chest to test for COVID-19. Test results will be available instantly. Please wait as it may take some time to process your input and make a prediction."
)

if __name__ == '__main__':
    iface.launch(inline=False)