from flask import Flask, render_template, request, jsonify
import os
import cv2
import numpy as np
from skimage.feature.texture import graycomatrix, graycoprops
from skimage.filters import gabor
from skimage.color import rgb2hsv
from skimage.segmentation import slic
from skimage.measure import regionprops
from sklearn.preprocessing import MinMaxScaler
import joblib
app = Flask(__name__)
# Directory to store uploaded files
UPLOAD_DIRECTORY = 'uploads'
RABIES_IMG_DIR = 'rabies_images'
NON_RABIES_IMG_DIR = 'non_rabies_images'
# Create the uploads directory if it doesn't exist
if not os.path.exists(UPLOAD_DIRECTORY):
os.makedirs(UPLOAD_DIRECTORY)
# Load trained model
clf_svm = joblib.load('SVM_model.joblib')
# Target size for image resizing
target_size = (224, 224)
# Function to preprocess an image
def preprocess_image(image_rgb, target_size):
try:
# Print type and shape of the input image
print("Input image - Type:", image_rgb.dtype, "Shape:", image_rgb.shape)
# Convert the image to grayscale
gray_image = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2GRAY)
# Ensure the grayscale image is of type CV_8UC1
if gray_image.dtype != np.uint8:
gray_image = gray_image.astype(np.uint8)
# Print type and shape of the grayscale image
print("Grayscale image - Type:", gray_image.dtype, "Shape:", gray_image.shape)
# Contrast Enhancement (CLAHE)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
enhanced_image = clahe.apply(gray_image)
# Convert the enhanced image back to RGB for further processing
enhanced_image_rgb = cv2.cvtColor(enhanced_image, cv2.COLOR_GRAY2RGB)
# Resize the enhanced image to the specified target size
img = cv2.resize(enhanced_image_rgb, target_size)
# Print type and shape of the preprocessed image
print("Preprocessed image - Type:", img.dtype, "Shape:", img.shape)
return img
except Exception as e:
print("Error during image preprocessing:", e)
return None
# Function to extract features from a preprocessed image
# Function to extract features from a preprocessed image
def extract_features(image_rgb, target_segments=100, max_iterations=20, max_features_range=(1000, 1100)):
try:
# Convert the RGB image to grayscale
gray_image = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2GRAY)
# GLCM (Gray-Level Co-occurrence Matrix)
glcm = graycomatrix(gray_image, distances=[5], angles=[0], levels=256, symmetric=True, normed=True)
contrast = graycoprops(glcm, 'contrast')[0][0]
homogeneity = graycoprops(glcm, 'homogeneity')[0][0]
energy = graycoprops(glcm, 'energy')[0][0]
# Gabor Filters
gabor_features = []
for sigma in (1, 3):
for frequency in (0.05, 0.25):
theta = np.pi / 4. # Use a fixed value for theta
kernel = np.real(gabor(gray_image, frequency, theta=theta, sigma_x=sigma, sigma_y=sigma))
gabor_features.append(np.mean(kernel))
# Color Histograms (HSV color space)
hsv_image = rgb2hsv(image_rgb)
h_hist, _ = np.histogram(hsv_image[:, :, 0], bins=256, range=(0, 1))
s_hist, _ = np.histogram(hsv_image[:, :, 1], bins=256, range=(0, 1))
v_hist, _ = np.histogram(hsv_image[:, :, 2], bins=256, range=(0, 1))
# Color-Based Segmentation with adjusted parameters
for _ in range(max_iterations):
segments = slic(image_rgb, n_segments=target_segments, compactness=20, sigma=3, start_label=1)
num_segments = len(np.unique(segments))
if num_segments == target_segments:
break
elif num_segments < target_segments:
target_segments -= 1
else:
target_segments += 1
else:
print(f"Warning: Unable to generate {target_segments} segments after {max_iterations} attempts. Skipping prediction.")
return None
# Geometric Features
segment_props = regionprops(segments)
area_list = [prop.area for prop in segment_props]
perimeter_list = [prop.perimeter for prop in segment_props]
eccentricity_list = [prop.eccentricity for prop in segment_props]
# Debug prints to investigate the number of segments and the length of the area list
print(f"Number of segments: {num_segments}")
print(f"Length of area list: {len(area_list)}")
# Scale features to [0, 1] range
scaler = MinMaxScaler()
contrast_scaled = scaler.fit_transform([[contrast]])[0]
homogeneity_scaled = scaler.fit_transform([[homogeneity]])[0]
energy_scaled = scaler.fit_transform([[energy]])[0]
gabor_features_scaled = scaler.fit_transform([gabor_features])[0]
h_hist_scaled = scaler.fit_transform([h_hist])[0]
s_hist_scaled = scaler.fit_transform([s_hist])[0]
v_hist_scaled = scaler.fit_transform([v_hist])[0]
area_scaled = scaler.fit_transform([area_list])[0]
perimeter_scaled = scaler.fit_transform([perimeter_list])[0]
eccentricity_scaled = scaler.fit_transform([eccentricity_list])[0]
# Combine all features into a single feature vector
feature_vector = np.concatenate([contrast_scaled, homogeneity_scaled, energy_scaled,
gabor_features_scaled, h_hist_scaled, s_hist_scaled,
v_hist_scaled, area_scaled, perimeter_scaled,
eccentricity_scaled])
# Truncate or pad the feature vector to ensure it falls within the specified range
min_features, max_features = max_features_range
if len(feature_vector) > max_features:
feature_vector = feature_vector[:max_features]
elif len(feature_vector) < min_features:
feature_vector = np.pad(feature_vector, (0, min_features - len(feature_vector)), 'constant')
return np.array(feature_vector) # Convert to array
except Exception as e:
print(f"Error during feature extraction: {e}")
return None
# Function to classify the image as rabies or non-rabies
def classify_image(image_path):
# Read the uploaded image
user_image = cv2.imread(image_path)
# Preprocess the image
preprocessed_img = preprocess_image(user_image, target_size)
if preprocessed_img is not None:
# Extract features from preprocessed image
features = extract_features(preprocessed_img)
if features is not None:
# Make predictions using SVM model
svm_prediction = clf_svm.predict(features.reshape(1, -1))
if svm_prediction is not None:
return "Suspected of Rabies" if svm_prediction == 1 else "Not Suspected of Rabies"
else:
return "Prediction Error"
else:
return "Feature Extraction Error"
else:
return "Image Preprocessing Error"
# Route for home page
@app.route('/')
def index():
return render_template('index.html')
# Route for image upload and classification
@app.route('/upload', methods=['POST'])
def upload():
if 'file' not in request.files:
return jsonify({'error': 'No file part'})
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'})
# Save the uploaded file
file_path = os.path.join(UPLOAD_DIRECTORY, file.filename)
file.save(file_path)
# Classify the uploaded image
result = classify_image(file_path)
return jsonify({'result': result})
if __name__ == '__main__':
app.run(debug=True)
When I ran the code above I get this error: [ValueError: X has 1066 features, but SVC is expecting 1060 features as input]. Any ideas on how to solve this?
I want user to upload their image of dog and my system will differentiate their picture with 2 directories that I have which is one directory containing images of rabies dogs and the others containing non-rabies images of dog. So the output will be whether their dog is suspected of rabies or not.
Emmanuel Matthew is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.