{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":24800,"datasetId":1042002,"databundleVersionId":1831594},{"sourceType":"datasetVersion","sourceId":1799615,"datasetId":1069544,"databundleVersionId":1837072}],"dockerImageVersionId":30761,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install ensemble-boxes","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-10-10T09:22:48.436185Z","iopub.execute_input":"2024-10-10T09:22:48.436624Z","iopub.status.idle":"2024-10-10T09:23:05.065335Z","shell.execute_reply.started":"2024-10-10T09:22:48.436583Z","shell.execute_reply":"2024-10-10T09:23:05.064152Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%matplotlib inline\n\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom matplotlib import rcParams\nsns.set(rc={\"font.size\":9,\"axes.titlesize\":15,\"axes.labelsize\":9,\n            \"axes.titlepad\":11, \"axes.labelpad\":9, \"legend.fontsize\":7,\n            \"legend.title_fontsize\":7, 'axes.grid' : False})\nimport cv2\nimport json\nimport pandas as pd\nimport glob\nimport os.path as osp\nfrom path import Path\nimport datetime\nimport numpy as np\nfrom tqdm.auto import tqdm\nimport random\nimport shutil\nfrom sklearn.model_selection import train_test_split\n\nfrom ensemble_boxes import *\nimport warnings\nfrom collections import Counter","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:23:16.025707Z","iopub.execute_input":"2024-10-10T09:23:16.026582Z","iopub.status.idle":"2024-10-10T09:23:19.239358Z","shell.execute_reply.started":"2024-10-10T09:23:16.026537Z","shell.execute_reply":"2024-10-10T09:23:19.238271Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Loading the Annotation CSV","metadata":{}},{"cell_type":"code","source":"train_annotations = pd.read_csv(\"../input/vinbigdata-competition-jpg-data-3x-downsampled/train_downsampled.csv\")\ntrain_annotations.head(5)","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:23:22.446892Z","iopub.execute_input":"2024-10-10T09:23:22.447512Z","iopub.status.idle":"2024-10-10T09:23:22.64988Z","shell.execute_reply.started":"2024-10-10T09:23:22.447468Z","shell.execute_reply":"2024-10-10T09:23:22.648739Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Selecting Images with Abnormalities","metadata":{}},{"cell_type":"code","source":"train_annotations = train_annotations[train_annotations.class_id!=14]\ntrain_annotations['image_path'] = train_annotations['image_id'].map(lambda x:os.path.join('../input/vinbigdata-competition-jpg-data-3x-downsampled/train/train', str(x)+'.jpg'))\ntrain_annotations.head(5)","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:23:25.693949Z","iopub.execute_input":"2024-10-10T09:23:25.694408Z","iopub.status.idle":"2024-10-10T09:23:25.821087Z","shell.execute_reply.started":"2024-10-10T09:23:25.694365Z","shell.execute_reply":"2024-10-10T09:23:25.820002Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"imagepaths = train_annotations['image_path'].unique()\nprint(\"Number of Images with abnormalities:\",len(imagepaths))\nanno_count = train_annotations.shape[0]\nprint(\"Number of Annotations with abnormalities:\", anno_count)","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:23:28.084524Z","iopub.execute_input":"2024-10-10T09:23:28.084922Z","iopub.status.idle":"2024-10-10T09:23:28.104528Z","shell.execute_reply.started":"2024-10-10T09:23:28.084884Z","shell.execute_reply":"2024-10-10T09:23:28.103483Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Helper Functions","metadata":{}},{"cell_type":"code","source":"def plot_img(img, size=(18, 18), is_rgb=True, title=\"\", cmap='gray'):\n    plt.figure(figsize=size)\n    plt.imshow(img, cmap=cmap)\n    plt.suptitle(title)\n    plt.show()\n\ndef plot_imgs(imgs, cols=2, size=10, is_rgb=True, title=\"\", cmap='gray', img_size=None):\n    rows = len(imgs)//cols + 1\n    fig = plt.figure(figsize=(cols*size, rows*size))\n    for i, img in enumerate(imgs):\n        if img_size is not None:\n            img = cv2.resize(img, img_size)\n        fig.add_subplot(rows, cols, i+1)\n        plt.imshow(img, cmap=cmap)\n    plt.suptitle(title)\n    \ndef draw_bbox(image, box, label, color):   \n    alpha = 0.1\n    alpha_box = 0.4\n    overlay_bbox = image.copy()\n    overlay_text = image.copy()\n    output = image.copy()\n\n    text_width, text_height = cv2.getTextSize(label.upper(), cv2.FONT_HERSHEY_SIMPLEX, 0.6, 1)[0]\n    cv2.rectangle(overlay_bbox, (box[0], box[1]), (box[2], box[3]),\n                color, -1)\n    cv2.addWeighted(overlay_bbox, alpha, output, 1 - alpha, 0, output)\n    cv2.rectangle(overlay_text, (box[0], box[1]-7-text_height), (box[0]+text_width+2, box[1]),\n                (0, 0, 0), -1)\n    cv2.addWeighted(overlay_text, alpha_box, output, 1 - alpha_box, 0, output)\n    cv2.rectangle(output, (box[0], box[1]), (box[2], box[3]),\n                    color, thickness)\n    cv2.putText(output, label.upper(), (box[0], box[1]-5),\n            cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1, cv2.LINE_AA)\n    return output","metadata":{"execution":{"iopub.status.busy":"2024-09-15T17:43:49.334698Z","iopub.execute_input":"2024-09-15T17:43:49.335344Z","iopub.status.idle":"2024-09-15T17:43:49.354649Z","shell.execute_reply.started":"2024-09-15T17:43:49.335277Z","shell.execute_reply":"2024-09-15T17:43:49.353328Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Visualize Original Bboxes","metadata":{}},{"cell_type":"code","source":"# map label_id to specify color\n#label2color = [[random.randint(0,255) for i in range(3)] for class_id in viz_labels]\nlabel2color = [[59, 238, 119], [222, 21, 229], [94, 49, 164], [206, 221, 133], [117, 75, 3],\n                 [210, 224, 119], [211, 176, 166], [63, 7, 197], [102, 65, 77], [194, 134, 175],\n                 [209, 219, 50], [255, 44, 47], [89, 125, 149], [110, 27, 100]]\n\nthickness = 3\nimgs = []\n\nfor img_id, path in zip(train_annotations['image_id'][:6], train_annotations['image_path'][:6]):\n\n    boxes = train_annotations.loc[train_annotations['image_id'] == img_id,\n                                  ['x_min', 'y_min', 'x_max', 'y_max']].values\n    img_labels = train_annotations.loc[train_annotations['image_id'] == img_id, ['class_id']].values.squeeze()\n    \n    img = cv2.imread(path)\n    \n    for label_id, box in zip(img_labels, boxes):\n        color = label2color[label_id]\n        img = draw_bbox(img, list(np.int_(box)), viz_labels[label_id], color)\n    imgs.append(img)\n\nplot_imgs(imgs, size=9, cmap=None)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-15T17:43:49.372946Z","iopub.execute_input":"2024-09-15T17:43:49.373547Z","iopub.status.idle":"2024-09-15T17:43:53.474817Z","shell.execute_reply.started":"2024-09-15T17:43:49.373456Z","shell.execute_reply":"2024-09-15T17:43:53.473159Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**### Weighted Boxes Fusion seems to give  gives better results comparing to others in this situation considering that we don't have the confidence/weights of the annotations done by different radiologists","metadata":{}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Building YOLO DATASET\n## Train, Validation & Test Split","metadata":{}},{"cell_type":"markdown","source":"Cú pháp cơ bản của định dạng YOLO\nMỗi file nhãn (label file) của YOLO sẽ có cùng tên với file ảnh tương ứng nhưng có phần mở rộng .txt. File này chứa một hoặc nhiều dòng, mỗi dòng mô tả một bounding box cho một đối tượng trong ảnh. Dưới đây là cú pháp cơ bản cho mỗi dòng trong file nhãn:\n\ncsharp\nCopy code\n<object-class> <x_center> <y_center> <width> <height>\nTrong đó:\n\n<object-class>: Chỉ số của lớp đối tượng (bắt đầu từ 0). Ví dụ: nếu bạn có 3 lớp: \"cat\", \"dog\", và \"person\", thì \"cat\" có thể có giá trị 0, \"dog\" có giá trị 1, và \"person\" có giá trị 2.\n<x_center>: Tọa độ x của tâm bounding box, được chuẩn hóa bằng chiều rộng của ảnh (nằm trong khoảng từ 0 đến 1).\n<y_center>: Tọa độ y của tâm bounding box, được chuẩn hóa bằng chiều cao của ảnh (nằm trong khoảng từ 0 đến 1).\n<width>: Chiều rộng của bounding box, được chuẩn hóa bằng chiều rộng của ảnh (nằm trong khoảng từ 0 đến 1).\n<height>: Chiều cao của bounding box, được chuẩn hóa bằng chiều cao của ảnh (nằm trong khoảng từ 0 đến 1).\nVí dụ về một file YOLO label\nGiả sử bạn có một ảnh image1.jpg với kích thước 1024x1024 pixels và file nhãn tương ứng image1.txt có nội dung sau:\n\nCopy code\n0 0.5 0.5 0.2 0.3\n1 0.7 0.8 0.1 0.1\nGiải thích:\n\nDòng 1: 0 0.5 0.5 0.2 0.3\n\n0: Đây là lớp đối tượng đầu tiên (ví dụ: \"cat\").\n0.5: Tọa độ x của tâm bounding box (50% từ cạnh trái của ảnh).\n0.5: Tọa độ y của tâm bounding box (50% từ cạnh trên của ảnh).\n0.2: Chiều rộng của bounding box (20% của chiều rộng ảnh).\n0.3: Chiều cao của bounding box (30% của chiều cao ảnh).\nDòng 2: 1 0.7 0.8 0.1 0.1\n\n1: Đây là lớp đối tượng thứ hai (ví dụ: \"dog\").\n0.7: Tọa độ x của tâm bounding box (70% từ cạnh trái của ảnh).\n0.8: Tọa độ y của tâm bounding box (80% từ cạnh trên của ảnh).\n0.1: Chiều rộng của bounding box (10% của chiều rộng ảnh).\n0.1: Chiều cao của bounding box (10% của chiều cao ảnh).","metadata":{}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Preprocessing\nIn the preprocessing, I used wbf and merged the boxes with iou=0.4.\nThis makes a single box created by multiple annotators.\nOne thing to keep in mind is that how many of the three annotators judged the disease.\nThere is a difference in how much confidence one can have in a disease box if only one person or two people or three people judges it to be a disease.\nI thought it is necessary to create a model that could account for the difference.\n\nFirst, I created three different training labels using the following methods.\n\nlabels-1: Leave boxes that are considered a disease by one or more annotators.\n\nlabels-2: Leave boxes that are considered a disease by two or more annotators.\n\nlabels-3: Leave boxes that are considered a disease by all three annotators.","metadata":{}},{"cell_type":"markdown","source":"### Tiền xử lý dữ liệu:\n### Sử dụng Weighted Boxes Fusion (WBF) để gộp các bounding box có IoU > 0.4\n### Tạo 3 bộ nhãn huấn luyện khác nhau:\n### a) labels-1: Giữ các box được ít nhất 1 người chú thích là bệnh\n### b) labels-2: Giữ các box được ít nhất 2 người chú thích là bệnh\n### c) labels-3: Giữ các box được cả 3 người chú thích là bệnh","metadata":{}},{"cell_type":"code","source":"yolo_dir = Path('./vinbigdata-yolo-dataset-with-wbf-3labels')\n    \n# label_sets = ['labels_1', 'labels_2', 'labels_3', 'labels_1_disease_only']\n\ndisplay_images_with_bboxes(yolo_dir, 'labels_1', 'train', num_images_to_display=10)","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:41:41.756843Z","iopub.execute_input":"2024-10-10T09:41:41.757768Z","iopub.status.idle":"2024-10-10T09:41:47.667147Z","shell.execute_reply.started":"2024-10-10T09:41:41.757712Z","shell.execute_reply":"2024-10-10T09:41:47.665977Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Generalized-Mean (GM)-WBF\n### Tổng quan: Một phần mở rộng của WBF thay thế trung bình trọng số bằng hàm trung bình tổng quát. Nó nhằm cung cấp một cơ chế hợp nhất mạnh mẽ hơn.\n### Ưu điểm: Có thể điều chỉnh để nhấn mạnh các phát hiện có độ tin cậy cao hoặc thấp, cung cấp sự linh hoạt hơn.\n### Thuật toán:\n### Tính toán trung bình tổng quát của các bounding box thay vì trung bình trọng số đơn giản.\n### Sử dụng một tham số để điều chỉnh sự nhấn mạnh lên các bounding box khác nhau.\n### Cải tiến so với WBF: Cung cấp chiến lược kết hợp linh hoạt hơn có thể điều chỉnh theo nhu cầu của ứng dụng cụ thể.","metadata":{}},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<object-class> <x_center> <y_center> <width> <height>\n","metadata":{}},{"cell_type":"code","source":"warnings.filterwarnings(\"ignore\", category=UserWarning)","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:44:06.552604Z","iopub.execute_input":"2024-10-10T09:44:06.553025Z","iopub.status.idle":"2024-10-10T09:44:06.558156Z","shell.execute_reply.started":"2024-10-10T09:44:06.552978Z","shell.execute_reply":"2024-10-10T09:44:06.556953Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!find ./vinbigdata-yolo-dataset-with-wbf-3labels -type f | wc -l","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:44:10.564Z","iopub.execute_input":"2024-10-10T09:44:10.564415Z","iopub.status.idle":"2024-10-10T09:44:12.466753Z","shell.execute_reply.started":"2024-10-10T09:44:10.564378Z","shell.execute_reply":"2024-10-10T09:44:12.465602Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Packaging Dataset into Zip for Upload","metadata":{}},{"cell_type":"code","source":"%%bash\ncd ./vinbigdata-yolo-dataset-with-wbf-3labels\nzip -rq ../vinbigdata-yolo-dataset-with-wbf-3labels.zip ./*\necho \"Zipping completed successfully.\"","metadata":{"execution":{"iopub.status.busy":"2024-10-10T09:44:15.734765Z","iopub.execute_input":"2024-10-10T09:44:15.735278Z","iopub.status.idle":"2024-10-10T09:54:53.536277Z","shell.execute_reply.started":"2024-10-10T09:44:15.735227Z","shell.execute_reply":"2024-10-10T09:54:53.533855Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%bash\nrm -r ./vinbigdata-yolo-dataset-with-wbf-3labels\nls -ahl","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-09-15T18:08:20.532135Z","iopub.execute_input":"2024-09-15T18:08:20.53277Z","iopub.status.idle":"2024-09-15T18:08:24.497275Z","shell.execute_reply.started":"2024-09-15T18:08:20.532702Z","shell.execute_reply":"2024-09-15T18:08:24.495643Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style='text-align: center;'><span style=\"color: #0D0D0D; font-family: Segoe UI; font-size: 2.0em; font-weight: 300;\">THANK YOU! PLEASE UPVOTE</span></p>\n\n<p style='text-align: center;'><span style=\"color: #0D0D0D; font-family: Segoe UI; font-size: 2.5em; font-weight: 300;\">HOPE IT WAS USEFUL</span></p>\n\n<p style='text-align: center;'><span style=\"color: #009BAE; font-family: Segoe UI; font-size: 1.2em; font-weight: 300;\">Check out the Train Notebook below</span></p>\n\n\n\n<p style='text-align: center;'><span style=\"font-family: Trebuchet MS; font-size: 1.3em;\"><a href=\"https://www.kaggle.com/code/buithanhxuan/vincxr-yolov8l\" target=\"_top\">vincxr-yolov8l⚡📈</a></span></p>\n\n<p style='text-align: center;'></p>\n","metadata":{}}]}