{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":19989,"databundleVersionId":1160143,"sourceType":"competition"},{"sourceId":11017618,"sourceType":"datasetVersion","datasetId":6860091},{"sourceId":289311,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":247871,"modelId":269389}],"dockerImageVersionId":29963,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# About this Notebook\n\nObject Detection is a problem which is not only a bit complex but also computationally expensive, due to the number of components to it. I always wanted to learn it and I got really excited when I saw a Kaggle competition on it , although I was not able to fully concentrate on it due to other competitions up untill now. While I was learning all the different concepts in Object Detection , I came across Facebook's **Detection tranformer DETR** , launched in April 2020 . It's still quite new but the resuts are astonishing and the model itself is very fast . In this notebook, I explore this new architecture,its working and fine tune it for Wheat Detection competition Dataset.\n\nNote that for now this is just a baseline to demonstrate the architecture and its working ,it does not aim at getting very good results on lb,this will be a work in progress,and I will soon update with full training and a separate ","metadata":{}},{"cell_type":"markdown","source":"# Update Log\n\n### V2\n* As I was made aware that I was printing the target boxes instead of predicted boxes , I have corrected it , I am really sorry , It was an honest mistake\n* Thanks to PRVI and his valuable suggestions , I have incorporated the following changes :\n  * Normalizing bounding boxes\n  * Using label 0 for main class\n\nThe code for the changes has been taken from [here](https://www.kaggle.com/prokaj/end-to-end-object-detection-with-transformers-detr#Creating-Dataset)","metadata":{}},{"cell_type":"markdown","source":"# DETR (Detection Transformer)\n\nAttention is all you need,paper for Transformers,changed the state of NLP and has achieved great hieghts. Though mainly developed for NLP , the latest research around it focuses on how to leverage it across different verticals of deep learning. Transformer acrhitecture is very very powerful, and is something which is very close to my part,this is the reason I am motivated to explore anything that uses transformers , be it google's recently released Tabnet or OpenAI's ImageGPT .\n\nDetection Transformer leverages the transformer network(both encoder and the decoder) for Detecting Objects in Images . Facebook's researchers argue that for object detection one part of the image should be in contact with the other part of the image for greater result especially with ocluded objects and partially visible objects, and what's better than to use transformer for it.\n\n**The main motive behind DETR is effectively removing the need for many hand-designed components like a non-maximum suppression procedure or anchor generation that explicitly encode prior knowledge about the task and makes the process complex and computationally expensive**\n\nThe main ingredients of the new framework, called DEtection TRansformer or DETR, <font color='green'>are a set-based global loss that forces unique predictions via bipartite matching, and a transformer encoder-decoder architecture.</font>\n\n![](https://cdn.analyticsvidhya.com/wp-content/uploads/2020/05/Screenshot-from-2020-05-27-17-48-38.png)\n\n<font color='red'>Interesting Right?? Want to learn more please bare with me, as always I will try to explain everything</font>","metadata":{}},{"cell_type":"markdown","source":"For Fully understanding DETR I recommend read [this](https://ai.facebook.com/blog/end-to-end-object-detection-with-transformers/) blog<br><br>\nHowever if you want in-depth knowledge and are a video person like please see the video in the cell below\nYou can find the video in youtube [here](https://www.youtube.com/watch?v=T35ba_VXkMY)","metadata":{}},{"cell_type":"markdown","source":"# Using DETR without Fine-Tuning\n\n* Before learning how to fine tune DETR if you want to use and play with DETR directly on some sample images , please refer the video [here](https://www.youtube.com/watch?v=LfUsGv-ESbc)\n* [Here](https://scontent.flko3-1.fna.fbcdn.net/v/t39.8562-6/101177000_245125840263462_1160672288488554496_n.pdf?_nc_cat=104&_nc_sid=ae5e01&_nc_ohc=KwU3i7_izOgAX9bxMVv&_nc_ht=scontent.flko3-1.fna&oh=64dad6ce7a7b4807bb3941690beaee69&oe=5F1E8347) is the link to the paper\n* [Here](https://github.com/facebookresearch/detr) is link to their github repo for code and model zoo\n* They recently added a wrapper to use DETR from Detectron2 API","metadata":{}},{"cell_type":"markdown","source":"# Wheat Detection Competition With DETR\n\nSo I wanted to try DETR and what could be greater oppurtunity than a kaggle competition to test a model's potential. I just joined two days ago and from what I have analyzed these are by far the best practices for this competition :-\n* Use Stratified Kfold because of different sources of Images\n* Use Cut-mix for better model generalization\n* Use WBF ensemble for unifying predictions of Kfold model\n\nBesides these I found gem of an EDA kernel , It gives very valuable insigts , you can have a look [here](https://www.kaggle.com/aleksandradeis/globalwheatdetection-eda) by aleksandra .Here are the conclusions derived from that kernel\n* Images are taken at different zoom levels. Crop and resize data augmentations to be used for model training.\n* Images are taken at various lighting conditions. Special filters should be used to address that.\n* Bounding boxes are messy!\n\n**There are some Giant bounding boxes and some micro bounding boxes removal of which have reported bad lb, so I assume the noise is present in the test setas well, hence keeping them would be more benificial**\n\nKeeping all this in find we start with coding DETR , **Note that this code can be used and easily modified to other object detection tasks**","metadata":{}},{"cell_type":"code","source":"!git clone https://github.com/facebookresearch/detr.git   #cloning github repo of detr to import its unique loss","metadata":{"trusted":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2025-03-19T08:45:47.218198Z","iopub.execute_input":"2025-03-19T08:45:47.218501Z","iopub.status.idle":"2025-03-19T08:45:50.273002Z","shell.execute_reply.started":"2025-03-19T08:45:47.218475Z","shell.execute_reply":"2025-03-19T08:45:50.272297Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"* Now if you have seen the video , you know that DETR uses a special loss called Bipartite Matching loss where it assigns one ground truth bbox to a predicted box using a matcher , thus when fine tuning we need the matcher (hungarian matcher as used in paper) and also the fucntion SetCriterion which gives Bipartite matching loss for backpropogation. This is the reason for forking the github repo","metadata":{}},{"cell_type":"markdown","source":"* So I did not know that we can add the path to environment variables using sys , hence I was changine directories , but now I have made changes so I do not have to change directories and import detr easily. A big Thanks to @prvi for his help","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np \nimport pandas as pd \nfrom datetime import datetime\nimport time\nimport random\nfrom tqdm.autonotebook import tqdm\n\n\n#Torch\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset,DataLoader\nfrom torch.utils.data.sampler import SequentialSampler, RandomSampler\n\n#sklearn\nfrom sklearn.model_selection import StratifiedKFold\n\n#CV\nimport cv2\n\n################# DETR FUCNTIONS FOR LOSS######################## \nimport sys\nsys.path.append('./detr/')\n\nfrom detr.models.matcher import HungarianMatcher\nfrom detr.models.detr import SetCriterion\n#################################################################\n\n#Albumenatations\nimport albumentations as A\nimport matplotlib.pyplot as plt\nfrom albumentations.pytorch.transforms import ToTensorV2\n\n#Glob\nfrom glob import glob","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:45:52.992433Z","iopub.execute_input":"2025-03-19T08:45:52.992732Z","iopub.status.idle":"2025-03-19T08:45:56.414836Z","shell.execute_reply.started":"2025-03-19T08:45:52.992702Z","shell.execute_reply":"2025-03-19T08:45:56.414181Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Utils\n\n* AverageMeter - class for averaging loss,metric,etc over epochs","metadata":{}},{"cell_type":"code","source":"class AverageMeter(object):\n    \"\"\"Computes and stores the average and current value\"\"\"\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:45:56.416505Z","iopub.execute_input":"2025-03-19T08:45:56.416759Z","iopub.status.idle":"2025-03-19T08:45:56.422084Z","shell.execute_reply.started":"2025-03-19T08:45:56.416736Z","shell.execute_reply":"2025-03-19T08:45:56.421352Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"n_folds = 5\nseed = 42\nnum_classes = 8\nnum_queries = 100\nnull_class_coef = 0.5\nBATCH_SIZE = 8\nLR = 2e-5\nEPOCHS = 50","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:45:59.422773Z","iopub.execute_input":"2025-03-19T08:45:59.423065Z","iopub.status.idle":"2025-03-19T08:45:59.427357Z","shell.execute_reply.started":"2025-03-19T08:45:59.423041Z","shell.execute_reply":"2025-03-19T08:45:59.426438Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Seed Everything\n\nSeeding everything for reproducible results","metadata":{}},{"cell_type":"code","source":"def seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:46:02.622977Z","iopub.execute_input":"2025-03-19T08:46:02.623344Z","iopub.status.idle":"2025-03-19T08:46:02.628187Z","shell.execute_reply.started":"2025-03-19T08:46:02.623305Z","shell.execute_reply":"2025-03-19T08:46:02.627431Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"seed_everything(seed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:46:04.927653Z","iopub.execute_input":"2025-03-19T08:46:04.928008Z","iopub.status.idle":"2025-03-19T08:46:04.934431Z","shell.execute_reply.started":"2025-03-19T08:46:04.92796Z","shell.execute_reply":"2025-03-19T08:46:04.933662Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model\n\n* Initial DETR model is trained on coco dataset , which has 91 classes + 1 background class , hence we need to modify it to take our own number of classes\n* Also DETR model takes in 100 queries ie ,it outputs total of 100 bboxes for every image , we can very well change that too","metadata":{}},{"cell_type":"code","source":"class DETRModel(nn.Module):\n    def __init__(self,num_classes,num_queries):\n        super(DETRModel,self).__init__()\n        self.num_classes = num_classes\n        self.num_queries = num_queries\n        \n        self.model = torch.hub.load('facebookresearch/detr', 'detr_resnet50', pretrained=True)\n        self.in_features = self.model.class_embed.in_features\n        \n        self.model.class_embed = nn.Linear(in_features=self.in_features,out_features=self.num_classes)\n        self.model.num_queries = self.num_queries\n        \n    def forward(self,images):\n        return self.model(images)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:46:17.761456Z","iopub.execute_input":"2025-03-19T08:46:17.761775Z","iopub.status.idle":"2025-03-19T08:46:17.768292Z","shell.execute_reply.started":"2025-03-19T08:46:17.761749Z","shell.execute_reply":"2025-03-19T08:46:17.767282Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport torch\nimport albumentations as A\nimport matplotlib.pyplot as plt\nfrom albumentations.pytorch import ToTensorV2\nimport pandas as pd\n\n# Charger les annotations réelles\ndef load_ground_truth(csv_path, image_id):\n    df = pd.read_csv(csv_path)\n    df = df[df[\"image_id\"] == image_id]\n    \n    gt_boxes = []\n    for bbox in df[\"bbox\"]:\n        bbox = eval(bbox)  # Convertir la chaîne en liste\n        x_min, y_min, width, height = map(int, bbox)  # Conversion en entiers\n        x_max, y_max = x_min + width, y_min + height\n        gt_boxes.append([x_min, y_min, x_max, y_max])\n    \n    return gt_boxes\n\n# Charger une image\ndef load_image(image_path):\n    image = cv2.imread(image_path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    return image\n\n# Fonction principale\ndef view_sample_from_path(image_path, image_id, model, device, csv_path, output_csv):\n    image = load_image(image_path)\n    h, w, _ = image.shape\n\n    # Charger les boîtes englobantes réelles\n    gt_boxes = load_ground_truth(csv_path, image_id)\n\n    # Transformation pour DETR\n    transform = A.Compose([\n        A.Resize(1024, 1024),\n        ToTensorV2()\n    ])\n    augmented = transform(image=image)\n    img_tensor = augmented[\"image\"].unsqueeze(0).to(device).float() / 255.0\n\n    # Prédiction du modèle\n    model.eval()\n    model.to(device)\n    with torch.no_grad():\n        outputs = model(img_tensor)\n\n    outputs = [{k: v.detach().cpu() for k, v in outputs.items()}]\n    pred_boxes = outputs[0]['pred_boxes'][0].numpy()\n    pred_scores = outputs[0]['pred_logits'][0].softmax(1).numpy()[:, 0]\n    pred_boxes = [list(map(int, np.array(box))) for box in A.augmentations.bbox_utils.denormalize_bboxes(pred_boxes, h, w)]\n\n    # Sauvegarde des prédictions\n    pred_data = []\n    for box, score in zip(pred_boxes, pred_scores):\n        if score > 0.25:  # Seuil de confiance\n            x_min, y_min, x_max, y_max = box\n            width, height = x_max - x_min, y_max - y_min\n            pred_data.append([image_id, f\"[{x_min}, {y_min}, {x_max}, {y_max}]\"])\n    \n    pred_df = pd.DataFrame(pred_data, columns=[\"image_id\", \"bbox\"])\n    pred_df.to_csv(output_csv, index=False)\n\n    # Affichage\n    fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n    sample = image.copy()\n\n    # Dessiner les boîtes réelles (rouge)\n    for box in gt_boxes:\n        x_min, y_min, x_max, y_max = map(int, box)\n        cv2.rectangle(sample, (x_min, y_min), (x_max, y_max), (255, 0, 0), 2)\n\n    # Dessiner les boîtes prédites (bleu)\n    for box, score in zip(pred_boxes, pred_scores):\n        if score > 0.7:  # Seuil de confiance\n            box[2]= box[2] + box[0]\n            box[3]= box[3] + box[1]\n            cv2.rectangle(sample, \n                          (box[0], box[1]), \n                          (box[2], box[3]), \n                          (0, 0, 255), 2)\n    ax.set_axis_off()\n    ax.imshow(sample)\n    plt.show()\n\n# Initialisation\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = DETRModel(num_classes=num_classes, num_queries=num_queries)\nmodel.load_state_dict(torch.load(\"/kaggle/input/models/pytorch/default/1/detr_best_0.pth\", map_location=device))\nmodel.to(device)\n\n# Spécifier l'image\nimage_id = \"image0010\"\nimage_path = f\"/kaggle/input/costum/test/{image_id}.jpg\"\ncsv_path = \"/kaggle/input/costum/test.csv\"\noutput_csv = \"/kaggle/working/predictions.csv\"\n\n# Exécuter la visualisation\nview_sample_from_path(image_path, image_id, model, device, csv_path, output_csv)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:46:59.517218Z","iopub.execute_input":"2025-03-19T08:46:59.517548Z","iopub.status.idle":"2025-03-19T08:47:15.184884Z","shell.execute_reply.started":"2025-03-19T08:46:59.517521Z","shell.execute_reply":"2025-03-19T08:47:15.183843Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Charger et afficher le fichier CSV\ncsv_path = \"/kaggle/working/predictions.csv\"\ndf = pd.read_csv(csv_path)\nprint(df.head())  # Afficher les premières lignes\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:47:22.147679Z","iopub.execute_input":"2025-03-19T08:47:22.147982Z","iopub.status.idle":"2025-03-19T08:47:22.157557Z","shell.execute_reply.started":"2025-03-19T08:47:22.147956Z","shell.execute_reply":"2025-03-19T08:47:22.156665Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport torch\nimport albumentations as A\nimport matplotlib.pyplot as plt\nfrom albumentations.pytorch import ToTensorV2\nimport pandas as pd\n\n# Charger les annotations réelles\ndef load_ground_truth(csv_path, image_id):\n    df = pd.read_csv(csv_path)\n    df = df[df[\"image_id\"] == image_id]\n    \n    gt_boxes = []\n    for bbox in df[\"bbox\"]:\n        bbox = eval(bbox)  # Convertir la chaîne en liste\n        x_min, y_min, width, height = map(int, bbox)  # Conversion en entiers\n        x_max, y_max = x_min + width, y_min + height\n        gt_boxes.append([x_min, y_min, x_max, y_max])\n    \n    return gt_boxes\n\n# Charger une image\ndef load_image(image_path):\n    image = cv2.imread(image_path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    return image\n\n# Fonction pour traiter une image\ndef process_image(image_path, image_id, model, device, csv_path):\n    image = load_image(image_path)\n    h, w, _ = image.shape\n\n    # Charger les boîtes réelles\n    gt_boxes = load_ground_truth(csv_path, image_id)\n\n    # Transformation pour DETR\n    transform = A.Compose([\n        A.Resize(1024, 1024),\n        ToTensorV2()\n    ])\n    augmented = transform(image=image)\n    img_tensor = augmented[\"image\"].unsqueeze(0).to(device).float() / 255.0\n\n    # Prédiction du modèle\n    model.eval()\n    model.to(device)\n    with torch.no_grad():\n        outputs = model(img_tensor)\n\n    outputs = [{k: v.detach().cpu() for k, v in outputs.items()}]\n    pred_boxes = outputs[0]['pred_boxes'][0].numpy()\n    pred_scores = outputs[0]['pred_logits'][0].softmax(1).numpy()[:, 0]\n    pred_boxes = [list(map(int, np.array(box))) for box in A.augmentations.bbox_utils.denormalize_bboxes(pred_boxes, h, w)]\n\n    # Stocker les prédictions\n    pred_data = []\n    for box, score in zip(pred_boxes, pred_scores):\n        if score > 0.5:  # Seuil de confiance\n\n            pred_data.append([image_id, f\"[{box[0]}, {box[1]}, {box[2]}, {box[3]}]\"])\n    \n    return pred_data\n\n# Fonction principale pour traiter tout un dossier\ndef process_directory(image_dir, model, device, csv_path, output_csv):\n    all_predictions = []\n\n    for filename in os.listdir(image_dir):\n        if filename.endswith(\".jpg\"):  # Vérifier les images\n            image_id = os.path.splitext(filename)[0]  # Récupérer le nom sans extension\n            image_path = os.path.join(image_dir, filename)\n            \n            pred_data = process_image(image_path, image_id, model, device, csv_path)\n            all_predictions.extend(pred_data)\n\n    # Sauvegarde des prédictions dans un fichier CSV\n    pred_df = pd.DataFrame(all_predictions, columns=[\"image_id\", \"bbox\"])\n    pred_df.to_csv(output_csv, index=False)\n    print(f\"Prédictions enregistrées dans {output_csv}\")\n\n# Initialisation\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = DETRModel(num_classes=num_classes, num_queries=num_queries)\nmodel.load_state_dict(torch.load(\"/kaggle/input/models/pytorch/default/1/detr_best_0.pth\", map_location=device))\nmodel.to(device)\n\n# Définition des chemins\nimage_dir = \"/kaggle/input/costum/test\"\ncsv_path = \"/kaggle/input/costum/test.csv\"\noutput_csv = \"/kaggle/working/predictions.csv\"\n\n# Exécuter le traitement sur toutes les images\nprocess_directory(image_dir, model, device, csv_path, output_csv)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:55:49.498108Z","iopub.execute_input":"2025-03-19T08:55:49.498459Z","iopub.status.idle":"2025-03-19T08:56:20.468669Z","shell.execute_reply.started":"2025-03-19T08:55:49.498425Z","shell.execute_reply":"2025-03-19T08:56:20.467763Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Charger et afficher le fichier CSV\ncsv_path = \"/kaggle/working/predictions.csv\"\ndf = pd.read_csv(csv_path)\nprint(df.head(400))  # Afficher les premières lignes\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:56:20.470415Z","iopub.execute_input":"2025-03-19T08:56:20.470772Z","iopub.status.idle":"2025-03-19T08:56:20.480202Z","shell.execute_reply.started":"2025-03-19T08:56:20.470735Z","shell.execute_reply":"2025-03-19T08:56:20.479564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport torch\nimport albumentations as A\nimport matplotlib.pyplot as plt\nfrom albumentations.pytorch import ToTensorV2\nimport pandas as pd\nimport random\n\n# Charger les annotations réelles\ndef load_ground_truth(csv_path):\n    df = pd.read_csv(csv_path)\n    gt_data = {}\n    for _, row in df.iterrows():\n        image_id = row[\"image_id\"]\n        x_min, y_min, width, height = eval(row[\"bbox\"])  # Convertir la chaîne en liste\n        x_max, y_max = x_min + width, y_min + height\n        if image_id not in gt_data:\n            gt_data[image_id] = []\n        gt_data[image_id].append([int(x_min), int(y_min), int(x_max), int(y_max)])\n    return gt_data\n\n# Charger les annotations prédites\ndef load_predictions(csv_path):\n    df = pd.read_csv(csv_path)\n    pred_data = {}\n    for _, row in df.iterrows():\n        image_id = row[\"image_id\"]\n        x_min, y_min, width, height = eval(row[\"bbox\"])  # Convertir la chaîne en liste\n        x_max, y_max = x_min + width, y_min + height\n        if image_id not in pred_data:\n            pred_data[image_id] = []\n        pred_data[image_id].append([int(x_min), int(y_min), int(x_max), int(y_max)])\n    return pred_data\n\n# Calcul de l'IoU\ndef calculate_iou(box1, box2):\n    x1_min, y1_min, x1_max, y1_max = box1\n    x2_min, y2_min, x2_max, y2_max = box2\n\n    inter_x_min = max(x1_min, x2_min)\n    inter_y_min = max(y1_min, y2_min)\n    inter_x_max = min(x1_max, x2_max)\n    inter_y_max = min(y1_max, y2_max)\n\n    inter_area = max(0, inter_x_max - inter_x_min) * max(0, inter_y_max - inter_y_min)\n    box1_area = (x1_max - x1_min) * (y1_max - y1_min)\n    box2_area = (x2_max - x2_min) * (y2_max - y2_min)\n\n    denominator = float(box1_area + box2_area - inter_area)\n    if denominator == 0:\n        return 0.0  # Éviter la division par zéro\n    \n    iou = inter_area / denominator\n    return iou\n\n# Évaluation des performances\ndef evaluate_performance(gt_boxes, pred_boxes, iou_threshold=0.5):\n    TP, FP, FN = 0, 0, 0\n    \n    for image_id in gt_boxes:\n        gt_bboxes = gt_boxes.get(image_id, [])\n        pred_bboxes = pred_boxes.get(image_id, [])\n        matched = []\n        \n        for gt in gt_bboxes:\n            best_iou = 0\n            best_pred = None\n            for pred in pred_bboxes:\n                iou = calculate_iou(gt, pred)\n                if iou > best_iou:\n                    best_iou = iou\n                    best_pred = pred\n            \n            if best_iou >= iou_threshold and best_pred is not None:\n                TP += 1\n                matched.append(best_pred)\n            else:\n                FN += 1\n        \n        FP += len(pred_bboxes) - len(matched)\n    \n    precision = TP / (TP + FP) if (TP + FP) > 0 else 0\n    recall = TP / (TP + FN) if (TP + FN) > 0 else 0\n    \n    return precision, recall, TP, FP, FN\n\n# Affichage de quelques images avec boîtes englobantes\ndef display_predictions(image_dir, gt_boxes, pred_boxes, num_images):\n    image_files = os.listdir(image_dir)\n    random.shuffle(image_files)\n    image_files = [f for f in image_files if f.endswith(\".jpg\")][:num_images]\n    \n    num_cols = 3\n    num_rows = (len(image_files) + num_cols - 1) // num_cols\n    fig, axes = plt.subplots(num_rows, num_cols, figsize=(15, 5 * num_rows))\n    axes = axes.flatten()\n    \n    for i, filename in enumerate(image_files):\n        image_id = os.path.splitext(filename)[0]\n        image_path = os.path.join(image_dir, filename)\n        image = cv2.imread(image_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        gt_bboxes = gt_boxes.get(image_id, [])\n        pred_bboxes = pred_boxes.get(image_id, [])\n        \n        for box in gt_bboxes:\n            x_min, y_min, x_max, y_max = map(int, box)\n            cv2.rectangle(image, (x_min, y_min), (x_max, y_max), (255, 0, 0), 2)  # Rouge pour GT\n        \n        for box in pred_bboxes:\n            x_min, y_min, x_max, y_max = map(int, box)\n            cv2.rectangle(image, (x_min, y_min), (x_max, y_max), (0, 0, 255), 2)  # Bleu pour prédictions\n        \n        axes[i].imshow(image)\n        axes[i].axis(\"off\")\n    \n    for j in range(i + 1, len(axes)):\n        axes[j].axis(\"off\")\n    \n    plt.tight_layout()\n    plt.show()\n\n# Chargement des données\ncsv_path_gt = \"/kaggle/input/costum/test.csv\"\ncsv_path_pred = \"/kaggle/working/predictions.csv\"\nimage_dir = \"/kaggle/input/costum/test\"\n\ngt_boxes = load_ground_truth(csv_path_gt)\npred_boxes = load_predictions(csv_path_pred)\n\n# Évaluation\niou_threshold = 0.5\nprecision, recall, TP, FP, FN = evaluate_performance(gt_boxes, pred_boxes, iou_threshold)\nprint(f\"Précision: {precision:.2f}, Rappel: {recall:.2f}\")\nprint(f\"TP: {TP}, FP: {FP}, FN: {FN}\")\nprint (\"accuracy: \", TP/(TP+FP+FN))\n\n# Affichage des prédictions\ndisplay_predictions(image_dir, gt_boxes, pred_boxes, num_images=363)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T09:30:09.835366Z","iopub.execute_input":"2025-03-19T09:30:09.835686Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport torch\nimport albumentations as A\nimport matplotlib.pyplot as plt\nfrom albumentations.pytorch import ToTensorV2\nimport pandas as pd\nimport random\n\n# Charger les annotations réelles\ndef load_ground_truth(csv_path):\n    df = pd.read_csv(csv_path)\n    gt_data = {}\n    for _, row in df.iterrows():\n        image_id = row[\"image_id\"]\n        x_min, y_min, width, height = eval(row[\"bbox\"])  # Convertir la chaîne en liste\n        x_max, y_max = x_min + width, y_min + height\n        if image_id not in gt_data:\n            gt_data[image_id] = []\n        gt_data[image_id].append([int(x_min), int(y_min), int(x_max), int(y_max)])\n    return gt_data\n\n# Charger les annotations prédites\ndef load_predictions(csv_path):\n    df = pd.read_csv(csv_path)\n    pred_data = {}\n    for _, row in df.iterrows():\n        image_id = row[\"image_id\"]\n        x_min, y_min, width, height = eval(row[\"bbox\"])  # Convertir la chaîne en liste\n        x_max, y_max = x_min + width, y_min + height\n        if image_id not in pred_data:\n            pred_data[image_id] = []\n        pred_data[image_id].append([int(x_min), int(y_min), int(x_max), int(y_max)])\n    return pred_data\n\n# Calcul de l'IoU\ndef calculate_iou(box1, box2):\n    x1_min, y1_min, x1_max, y1_max = box1\n    x2_min, y2_min, x2_max, y2_max = box2\n\n    inter_x_min = max(x1_min, x2_min)\n    inter_y_min = max(y1_min, y2_min)\n    inter_x_max = min(x1_max, x2_max)\n    inter_y_max = min(y1_max, y2_max)\n\n    inter_area = max(0, inter_x_max - inter_x_min) * max(0, inter_y_max - inter_y_min)\n    box1_area = (x1_max - x1_min) * (y1_max - y1_min)\n    box2_area = (x2_max - x2_min) * (y2_max - y2_min)\n\n    denominator = float(box1_area + box2_area - inter_area)\n    if denominator == 0:\n        return 0.0  # Éviter la division par zéro\n    \n    iou = inter_area / denominator\n    return iou\n\n# Évaluation des performances\ndef evaluate_performance(gt_boxes, pred_boxes, iou_threshold=0.5):\n    TP, FP, FN = 0, 0, 0\n    \n    for image_id in gt_boxes:\n        gt_bboxes = gt_boxes.get(image_id, [])\n        pred_bboxes = pred_boxes.get(image_id, [])\n        matched = []\n        \n        for gt in gt_bboxes:\n            best_iou = 0\n            best_pred = None\n            for pred in pred_bboxes:\n                iou = calculate_iou(gt, pred)\n                if iou > best_iou:\n                    best_iou = iou\n                    best_pred = pred\n            \n            if best_iou >= iou_threshold and best_pred is not None:\n                TP += 1\n                matched.append(best_pred)\n            else:\n                FN += 1\n        \n        FP += len(pred_bboxes) - len(matched)\n    \n    precision = TP / (TP + FP) if (TP + FP) > 0 else 0\n    recall = TP / (TP + FN) if (TP + FN) > 0 else 0\n    \n    return precision, recall, TP, FP, FN\n\n# Affichage de quelques images avec boîtes englobantes\ndef display_predictions(image_dir, gt_boxes, pred_boxes, num_images=20):\n    image_files = os.listdir(image_dir)\n    random.shuffle(image_files)\n    image_files = [f for f in image_files if f.endswith(\".jpg\")][:num_images]\n    \n    for filename in image_files:\n        image_id = os.path.splitext(filename)[0]\n        image_path = os.path.join(image_dir, filename)\n        image = cv2.imread(image_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        gt_bboxes = gt_boxes.get(image_id, [])\n        pred_bboxes = pred_boxes.get(image_id, [])\n        \n        for box in gt_bboxes:\n            x_min, y_min, x_max, y_max = map(int, box)\n            cv2.rectangle(image, (x_min, y_min), (x_max, y_max), (255, 0, 0), 2)  # Rouge pour GT\n        \n        for box in pred_bboxes:\n            x_min, y_min, x_max, y_max = map(int, box)\n            cv2.rectangle(image, (x_min, y_min), (x_max, y_max), (0, 0, 255), 2)  # Bleu pour prédictions\n        \n        plt.figure(figsize=(8, 8))\n        plt.imshow(image)\n        plt.axis(\"off\")\n        plt.show()\n\n# Chargement des données\ncsv_path_gt = \"/kaggle/input/costum/test.csv\"\ncsv_path_pred = \"/kaggle/working/predictions.csv\"\nimage_dir = \"/kaggle/input/costum/test\"\n\ngt_boxes = load_ground_truth(csv_path_gt)\npred_boxes = load_predictions(csv_path_pred)\n\n# Évaluation\niou_threshold = 0.5\nprecision, recall, TP, FP, FN = evaluate_performance(gt_boxes, pred_boxes, iou_threshold)\nprint(f\"Précision: {precision:.2f}, Rappel: {recall:.2f}\")\nprint(f\"TP: {TP}, FP: {FP}, FN: {FN}\")\nprint (\"accuracy: \", TP/(TP+FP+FN))\n# Affichage des prédictions\ndisplay_predictions(image_dir, gt_boxes, pred_boxes, num_images=20)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-19T08:56:26.029688Z","iopub.execute_input":"2025-03-19T08:56:26.029975Z","iopub.status.idle":"2025-03-19T08:56:31.168392Z","shell.execute_reply.started":"2025-03-19T08:56:26.029951Z","shell.execute_reply":"2025-03-19T08:56:31.167626Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null}]}