# -*- coding: utf-8 -*- """ Created on Sat Jun 15 17:15:51 2024 @author: Proprietaire """ import os import numpy as np from PIL import Image from skimage import io, draw, color from skimage.feature import hog from skimage.color import rgb2hsv, rgb2gray from skimage.segmentation import felzenszwalb from skimage.measure import regionprops from sklearn import svm from sklearn.metrics import accuracy_score from skimage.transform import pyramid_gaussian from sklearn.cluster import DBSCAN import matplotlib.pyplot as plt AVERAGE_SIZE_IMAGE = (127, 145) # Utilitaire pour générer une bbox vide pour les images sans label def generate_empty_bbox(image_width, image_height): x_min = np.random.randint(0, image_width - AVERAGE_SIZE_IMAGE[0]) y_min = np.random.randint(0, image_height - AVERAGE_SIZE_IMAGE[1]) x_max = x_min + AVERAGE_SIZE_IMAGE[0] y_max = y_min + AVERAGE_SIZE_IMAGE[1] return (x_min, y_min, x_max, y_max) # Chargement des données def load_data(image_dir, label_dir): datas = {} for image_file in os.listdir(image_dir): image_path = os.path.join(image_dir, image_file) name = image_file.split('.')[0] label_path = os.path.join(label_dir, f"{name}.csv") image = np.array(Image.open(image_path)) with open(label_path, 'r') as file: rows = file.readlines() label_data = {} if rows == ['\n']: xmin, ymin, xmax, ymax = generate_empty_bbox(image.shape[1], image.shape[0]) cropped_image = np.array(Image.fromarray(image[ymin:ymax, xmin:xmax]).resize(AVERAGE_SIZE_IMAGE)) label_data[0] = { "name": "empty", "coord": (xmin, ymin, xmax, ymax), "img": cropped_image } else: for i, row in enumerate(rows): row = row.strip().split(",") xmin, ymin, xmax, ymax = map(int, row[0:4]) class_name = row[4] cropped_image = np.array(Image.fromarray(image[ymin:ymax, xmin:xmax]).resize(AVERAGE_SIZE_IMAGE)) label_data[i] = { "name": class_name, "coord": (xmin, ymin, xmax, ymax), "img": cropped_image } datas[name] = { "img": image, "labels": label_data, } return datas # Dict pour convertir les noms de classe en entiers name_to_int = { "danger": 0, "interdiction": 1, "obligation": 2, "stop": 3, "ceder": 4, "frouge": 5, "forange": 6, "fvert": 7, "ff": 8, "empty": 9 } ###################################################################################### ###################################################################################### # Création des caractéristiques HOG pour la détection def regions_to_vectors_stop(datas): X = [] Y = [] for name, data in datas.items(): image = data["img"] labels = data["labels"] for label in labels.values(): region = label["img"] # Récupérer la région labellisée # Appliquer un prétraitement si nécessaire (redimensionnement, mise à l'échelle, etc.) hog_features = np.array(hog(rgb2gray(region), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten() class_label = name_to_int[label["name"]] if class_label == name_to_int["stop"]: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(1) # Panneau stop else: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(0) # Non-stop (autres classes) return np.array(X), np.array(Y) def regions_to_vectors_danger(datas): X = [] Y = [] for name, data in datas.items(): image = data["img"] labels = data["labels"] for label in labels.values(): region = label["img"] # Récupérer la région labellisée # Appliquer un prétraitement si nécessaire (redimensionnement, mise à l'échelle, etc.) hog_features = np.array(hog(rgb2gray(region), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten() class_label = name_to_int[label["name"]] if class_label == name_to_int["danger"]: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(1) # Panneau danger else: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(0) # Non-danger (autres classes) return np.array(X), np.array(Y) def regions_to_vectors_interdiction(datas): X = [] Y = [] for name, data in datas.items(): image = data["img"] labels = data["labels"] for label in labels.values(): region = label["img"] # Récupérer la région labellisée # Appliquer un prétraitement si nécessaire (redimensionnement, mise à l'échelle, etc.) hog_features = np.array(hog(rgb2gray(region), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten() class_label = name_to_int[label["name"]] if class_label == name_to_int["interdiction"]: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(1) # Panneau interdiction else: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(0) # Non-interdiction (autres classes) return np.array(X), np.array(Y) def regions_to_vectors_obligation(datas): X = [] Y = [] for name, data in datas.items(): image = data["img"] labels = data["labels"] for label in labels.values(): region = label["img"] # Récupérer la région labellisée # Appliquer un prétraitement si nécessaire (redimensionnement, mise à l'échelle, etc.) hog_features = np.array(hog(rgb2gray(region), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten() class_label = name_to_int[label["name"]] if class_label == name_to_int["obligation"]: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(1) # Panneau obligation else: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(0) # Non-obligation (autres classes) return np.array(X), np.array(Y) def regions_to_vectors_ceder(datas): X = [] Y = [] for name, data in datas.items(): image = data["img"] labels = data["labels"] for label in labels.values(): region = label["img"] # Récupérer la région labellisée # Appliquer un prétraitement si nécessaire (redimensionnement, mise à l'échelle, etc.) hog_features = np.array(hog(rgb2gray(region), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten() class_label = name_to_int[label["name"]] if class_label == name_to_int["ceder"]: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(1) # Panneau ceder else: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(0) # Non-ceder (autres classes) return np.array(X), np.array(Y) def regions_to_vectors_feu(datas): X = [] Y = [] for name, data in datas.items(): image = data["img"] labels = data["labels"] for label in labels.values(): region = label["img"] # Récupérer la région labellisée # Appliquer un prétraitement si nécessaire (redimensionnement, mise à l'échelle, etc.) hog_features = np.array(hog(rgb2gray(region), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten() class_label = name_to_int[label["name"]] if class_label == name_to_int["frouge"] or class_label == name_to_int["forange"] or class_label == name_to_int["fvert"]: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(1) # Feu else: X.append(hog_features) # Ajouter les caractéristiques HOG Y.append(0) # Non-feu (autres classes) return np.array(X), np.array(Y) ###################################################################################### ###################################################################################### # Entraînement du modèle SVM avec les caractéristiques HOG datas_train = load_data("dataset-main-train/train/images", "dataset-main-train/train/labels") datas_val = load_data("dataset-main-val/val/images", "dataset-main-val/val/labels") # Dossier contenant les images d'évaluation test_image_folder = 'dataset-main-val/val/images' output_folder_stop = 'result_detection_v2_stop' output_folder_danger = 'result_detection_v2_danger' output_folder_interdiction = 'result_detection_v2_interdiction' output_folder_obligation = 'result_detection_v2_obligation' output_folder_ceder = 'result_detection_v2_ceder' output_folder_feu = 'result_detection_v2_feu' X_train_stop, Y_train_stop = regions_to_vectors_stop(datas_train) X_val_stop, Y_val_stop = regions_to_vectors_stop(datas_val) X_train_danger, Y_train_danger = regions_to_vectors_danger(datas_train) X_val_danger, Y_val_danger = regions_to_vectors_danger(datas_val) X_train_interdiction, Y_train_interdiction = regions_to_vectors_interdiction(datas_train) X_val_interdiction, Y_val_interdiction = regions_to_vectors_interdiction(datas_val) X_train_obligation, Y_train_obligation = regions_to_vectors_obligation(datas_train) X_val_obligation, Y_val_obligation = regions_to_vectors_obligation(datas_val) X_train_ceder, Y_train_ceder = regions_to_vectors_ceder(datas_train) X_val_ceder, Y_val_ceder = regions_to_vectors_ceder(datas_val) X_train_feu, Y_train_feu = regions_to_vectors_feu(datas_train) X_val_feu, Y_val_feu = regions_to_vectors_feu(datas_val) ###################################################################################### ###################################################################################### # Créer et entraîner le classifieur SVM pour les panneaux stop clf_stop = svm.SVC(kernel='poly') clf_stop.fit(X_train_stop, Y_train_stop) # Prédiction sur le jeu de validation y_pred = clf_stop.predict(X_val_stop) print(f"Taux d'erreur SVM pour panneaux stop: {np.mean(y_pred != Y_val_stop)}") clf_danger = svm.SVC(kernel='poly') clf_danger.fit(X_train_danger, Y_train_danger) # Prédiction sur le jeu de validation y_pred = clf_danger.predict(X_val_danger) print(f"Taux d'erreur SVM pour panneaux danger: {np.mean(y_pred != Y_val_danger)}") clf_interdiction = svm.SVC(kernel='poly') clf_interdiction.fit(X_train_interdiction, Y_train_interdiction) # Prédiction sur le jeu de validation y_pred = clf_interdiction.predict(X_val_interdiction) print(f"Taux d'erreur SVM pour panneaux interdiction: {np.mean(y_pred != Y_val_interdiction)}") clf_obligation = svm.SVC(kernel='poly') clf_obligation.fit(X_train_obligation, Y_train_obligation) # Prédiction sur le jeu de validation y_pred = clf_obligation.predict(X_val_obligation) print(f"Taux d'erreur SVM pour panneaux obligation: {np.mean(y_pred != Y_val_obligation)}") clf_ceder = svm.SVC(kernel='poly') clf_ceder.fit(X_train_ceder, Y_train_ceder) # Prédiction sur le jeu de validation y_pred = clf_ceder.predict(X_val_ceder) print(f"Taux d'erreur SVM pour panneaux ceder: {np.mean(y_pred != Y_val_ceder)}") clf_feu = svm.SVC(kernel='poly') clf_feu.fit(X_train_feu, Y_train_feu) # Prédiction sur le jeu de validation y_pred = clf_feu.predict(X_val_feu) print(f"Taux d'erreur SVM pour panneaux feu: {np.mean(y_pred != Y_val_feu)}") #################################################################################### #################################################################################### # Fonction pour faire glisser une fenêtre sur l'image def sliding_window(image, step_size, window_size): for y in range(0, image.shape[0] - window_size[1], step_size): for x in range(0, image.shape[1] - window_size[0], step_size): yield (x, y, image[y:y + window_size[1], x:x + window_size[0]]) # Fonction pour la suppression des doublons (NMS) def non_max_suppression(boxes, overlap_thresh=0.3): if len(boxes) == 0: return [] boxes = np.array(boxes) if boxes.dtype.kind == "i": boxes = boxes.astype("float") pick = [] x1 = boxes[:,0] y1 = boxes[:,1] x2 = boxes[:,2] y2 = boxes[:,3] area = (x2 - x1 + 1) * (y2 - y1 + 1) idxs = np.argsort(y2) while len(idxs) > 0: last = len(idxs) - 1 i = idxs[last] pick.append(i) xx1 = np.maximum(x1[i], x1[idxs[:last]]) yy1 = np.maximum(y1[i], y1[idxs[:last]]) xx2 = np.minimum(x2[i], x2[idxs[:last]]) yy2 = np.minimum(y2[i], y2[idxs[:last]]) w = np.maximum(0, xx2 - xx1 + 1) h = np.maximum(0, yy2 - yy1 + 1) overlap = (w * h) / area[idxs[:last]] idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlap_thresh)[0]))) return boxes[pick].astype("int") # Préparation du dossier de sortie if not os.path.exists(output_folder_stop): os.makedirs(output_folder_stop) if not os.path.exists(output_folder_danger): os.makedirs(output_folder_danger) if not os.path.exists(output_folder_interdiction): os.makedirs(output_folder_interdiction) if not os.path.exists(output_folder_obligation): os.makedirs(output_folder_obligation) if not os.path.exists(output_folder_ceder): os.makedirs(output_folder_ceder) if not os.path.exists(output_folder_feu): os.makedirs(output_folder_feu) ###################################################################################### ###################################################################################### #Fonction prediction? """ def prediction(hog_features): if clf_stop.predict(hog_features)==1: return "stop" if clf_danger.predict(hog_features)==1: return "danger" if clf_interdiction.predict(hog_features)==1: return "interdiction" if clf_obligation.predict(hog_features)==1: return "obligation" """ ###################################################################################### ###################################################################################### ###################################################################################### #Detection et classification window_sizes = [(64, 64), (128, 128), (256, 256),(512,512)] # Différentes tailles de fenêtres step_size = 32 stop=0 danger=0 interdiction=0 obligation=0 ceder=0 feu=0 for filename in os.listdir(test_image_folder): test_image_path = os.path.join(test_image_folder, filename) test_image = io.imread(test_image_path) detections = [] for window_size in window_sizes: for (x, y, window) in sliding_window(test_image, step_size=step_size, window_size=window_size): if window.shape[0] != window_size[1] or window.shape[1] != window_size[0]: continue # Extraire les caractéristiques HOG de la fenêtre window_resized = np.array(Image.fromarray(window).resize(AVERAGE_SIZE_IMAGE)) hog_features = np.array(hog(rgb2gray(window_resized), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten().reshape(1, -1) #pred = prediction(hog_features) pred=clf_stop.predict(hog_features) if pred==1: detections.append((x, y, x + window_size[0], y + window_size[1])) """ if pred == "stop": detections.append((x, y, x + window_size[0], y + window_size[1])) stop=stop+1 elif pred == "danger": detections.append((x, y, x + window_size[0], y + window_size[1])) danger=danger+1 elif pred == "interdiction": detections.append((x, y, x + window_size[0], y + window_size[1])) interdiction=interdiction+1 elif pred == "obligation": detections.append((x, y, x + window_size[0], y + window_size[1])) obligation=obligation+1 """ # Suppression des doublons (NMS) nms_boxes = non_max_suppression(detections, overlap_thresh=0.3) for (x1, y1, x2, y2) in nms_boxes: rr, cc = draw.rectangle_perimeter(start=(y1, x1), extent=(y2 - y1, x2 - x1), shape=test_image.shape) test_image[rr, cc] = [255, 0, 0] stop=stop+1 output_path = os.path.join(output_folder_stop, filename) io.imsave(output_path, test_image) print(f"Processed and saved: {filename}") for filename in os.listdir(test_image_folder): test_image_path = os.path.join(test_image_folder, filename) test_image = io.imread(test_image_path) detections = [] for window_size in window_sizes: for (x, y, window) in sliding_window(test_image, step_size=step_size, window_size=window_size): if window.shape[0] != window_size[1] or window.shape[1] != window_size[0]: continue # Extraire les caractéristiques HOG de la fenêtre window_resized = np.array(Image.fromarray(window).resize(AVERAGE_SIZE_IMAGE)) hog_features = np.array(hog(rgb2gray(window_resized), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten().reshape(1, -1) #pred = prediction(hog_features) pred=clf_danger.predict(hog_features) if pred==1: detections.append((x, y, x + window_size[0], y + window_size[1])) """ if pred == "stop": detections.append((x, y, x + window_size[0], y + window_size[1])) stop=stop+1 elif pred == "danger": detections.append((x, y, x + window_size[0], y + window_size[1])) danger=danger+1 elif pred == "interdiction": detections.append((x, y, x + window_size[0], y + window_size[1])) interdiction=interdiction+1 elif pred == "obligation": detections.append((x, y, x + window_size[0], y + window_size[1])) obligation=obligation+1 """ # Suppression des doublons (NMS) nms_boxes = non_max_suppression(detections, overlap_thresh=0.3) for (x1, y1, x2, y2) in nms_boxes: rr, cc = draw.rectangle_perimeter(start=(y1, x1), extent=(y2 - y1, x2 - x1), shape=test_image.shape) test_image[rr, cc] = [255, 0, 0] danger=danger+1 output_path = os.path.join(output_folder_danger, filename) io.imsave(output_path, test_image) print(f"Processed and saved: {filename}") for filename in os.listdir(test_image_folder): test_image_path = os.path.join(test_image_folder, filename) test_image = io.imread(test_image_path) detections = [] for window_size in window_sizes: for (x, y, window) in sliding_window(test_image, step_size=step_size, window_size=window_size): if window.shape[0] != window_size[1] or window.shape[1] != window_size[0]: continue # Extraire les caractéristiques HOG de la fenêtre window_resized = np.array(Image.fromarray(window).resize(AVERAGE_SIZE_IMAGE)) hog_features = np.array(hog(rgb2gray(window_resized), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten().reshape(1, -1) #pred = prediction(hog_features) pred=clf_interdiction.predict(hog_features) if pred==1: detections.append((x, y, x + window_size[0], y + window_size[1])) """ if pred == "stop": detections.append((x, y, x + window_size[0], y + window_size[1])) stop=stop+1 elif pred == "danger": detections.append((x, y, x + window_size[0], y + window_size[1])) danger=danger+1 elif pred == "interdiction": detections.append((x, y, x + window_size[0], y + window_size[1])) interdiction=interdiction+1 elif pred == "obligation": detections.append((x, y, x + window_size[0], y + window_size[1])) obligation=obligation+1 """ # Suppression des doublons (NMS) nms_boxes = non_max_suppression(detections, overlap_thresh=0.3) for (x1, y1, x2, y2) in nms_boxes: rr, cc = draw.rectangle_perimeter(start=(y1, x1), extent=(y2 - y1, x2 - x1), shape=test_image.shape) test_image[rr, cc] = [255, 0, 0] interdiction=interdiction+1 output_path = os.path.join(output_folder_interdiction, filename) io.imsave(output_path, test_image) print(f"Processed and saved: {filename}") for filename in os.listdir(test_image_folder): test_image_path = os.path.join(test_image_folder, filename) test_image = io.imread(test_image_path) detections = [] for window_size in window_sizes: for (x, y, window) in sliding_window(test_image, step_size=step_size, window_size=window_size): if window.shape[0] != window_size[1] or window.shape[1] != window_size[0]: continue # Extraire les caractéristiques HOG de la fenêtre window_resized = np.array(Image.fromarray(window).resize(AVERAGE_SIZE_IMAGE)) hog_features = np.array(hog(rgb2gray(window_resized), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten().reshape(1, -1) #pred = prediction(hog_features) pred=clf_obligation.predict(hog_features) if pred==1: detections.append((x, y, x + window_size[0], y + window_size[1])) """ if pred == "stop": detections.append((x, y, x + window_size[0], y + window_size[1])) stop=stop+1 elif pred == "danger": detections.append((x, y, x + window_size[0], y + window_size[1])) danger=danger+1 elif pred == "interdiction": detections.append((x, y, x + window_size[0], y + window_size[1])) interdiction=interdiction+1 elif pred == "obligation": detections.append((x, y, x + window_size[0], y + window_size[1])) obligation=obligation+1 """ # Suppression des doublons (NMS) nms_boxes = non_max_suppression(detections, overlap_thresh=0.3) for (x1, y1, x2, y2) in nms_boxes: rr, cc = draw.rectangle_perimeter(start=(y1, x1), extent=(y2 - y1, x2 - x1), shape=test_image.shape) test_image[rr, cc] = [255, 0, 0] obligation=obligation+1 output_path = os.path.join(output_folder_obligation, filename) io.imsave(output_path, test_image) print(f"Processed and saved: {filename}") for filename in os.listdir(test_image_folder): test_image_path = os.path.join(test_image_folder, filename) test_image = io.imread(test_image_path) detections = [] for window_size in window_sizes: for (x, y, window) in sliding_window(test_image, step_size=step_size, window_size=window_size): if window.shape[0] != window_size[1] or window.shape[1] != window_size[0]: continue # Extraire les caractéristiques HOG de la fenêtre window_resized = np.array(Image.fromarray(window).resize(AVERAGE_SIZE_IMAGE)) hog_features = np.array(hog(rgb2gray(window_resized), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten().reshape(1, -1) #pred = prediction(hog_features) pred=clf_ceder.predict(hog_features) if pred==1: detections.append((x, y, x + window_size[0], y + window_size[1])) """ if pred == "stop": detections.append((x, y, x + window_size[0], y + window_size[1])) stop=stop+1 elif pred == "danger": detections.append((x, y, x + window_size[0], y + window_size[1])) danger=danger+1 elif pred == "interdiction": detections.append((x, y, x + window_size[0], y + window_size[1])) interdiction=interdiction+1 elif pred == "obligation": detections.append((x, y, x + window_size[0], y + window_size[1])) obligation=obligation+1 """ # Suppression des doublons (NMS) nms_boxes = non_max_suppression(detections, overlap_thresh=0.3) for (x1, y1, x2, y2) in nms_boxes: rr, cc = draw.rectangle_perimeter(start=(y1, x1), extent=(y2 - y1, x2 - x1), shape=test_image.shape) test_image[rr, cc] = [255, 0, 0] ceder=ceder+1 output_path = os.path.join(output_folder_ceder, filename) io.imsave(output_path, test_image) print(f"Processed and saved: {filename}") for filename in os.listdir(test_image_folder): test_image_path = os.path.join(test_image_folder, filename) test_image = io.imread(test_image_path) detections = [] for window_size in window_sizes: for (x, y, window) in sliding_window(test_image, step_size=step_size, window_size=window_size): if window.shape[0] != window_size[1] or window.shape[1] != window_size[0]: continue # Extraire les caractéristiques HOG de la fenêtre window_resized = np.array(Image.fromarray(window).resize(AVERAGE_SIZE_IMAGE)) hog_features = np.array(hog(rgb2gray(window_resized), pixels_per_cell=(16, 16), cells_per_block=(2, 2), block_norm='L2-Hys')).flatten().reshape(1, -1) #pred = prediction(hog_features) pred=clf_feu.predict(hog_features) if pred==1: detections.append((x, y, x + window_size[0], y + window_size[1])) """ if pred == "stop": detections.append((x, y, x + window_size[0], y + window_size[1])) stop=stop+1 elif pred == "danger": detections.append((x, y, x + window_size[0], y + window_size[1])) danger=danger+1 elif pred == "interdiction": detections.append((x, y, x + window_size[0], y + window_size[1])) interdiction=interdiction+1 elif pred == "obligation": detections.append((x, y, x + window_size[0], y + window_size[1])) obligation=obligation+1 """ # Suppression des doublons (NMS) nms_boxes = non_max_suppression(detections, overlap_thresh=0.3) for (x1, y1, x2, y2) in nms_boxes: rr, cc = draw.rectangle_perimeter(start=(y1, x1), extent=(y2 - y1, x2 - x1), shape=test_image.shape) test_image[rr, cc] = [255, 0, 0] feu=feu+1 output_path = os.path.join(output_folder_feu, filename) io.imsave(output_path, test_image) print(f"Processed and saved: {filename}") print("Panneaux stop détectés :", stop) print("Panneaux danger détectés :", danger) print("Panneaux interdiction détectés :", interdiction) print("Panneaux obligation détectés :", obligation) print("Panneaux ceder détectés :", ceder) print("Panneaux feu détectés :", feu)