{"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":8264904,"sourceType":"datasetVersion","datasetId":4906141}],"dockerImageVersionId":30005,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Note for our team members:\n## 1. Ctrl + F: search TODO. (3 list)\n## 2. Replace the list with the selected images.\n## 3. Download Kaggle Working (or Output).\n## 4. Re-check the augmented images in the 'check' folder\n## 5. Keep/remove the appropriate images.\n\nPlease don’t hesitate to contact me (huong) if you have any problems","metadata":{}},{"cell_type":"markdown","source":"# Import Library","metadata":{}},{"cell_type":"code","source":"import os\nimport re\nimport cv2\nimport ast\nimport random\nimport pandas as pd\nimport numpy as np\n\nfrom PIL import Image\nimport albumentations as A\nfrom collections import namedtuple\nfrom albumentations.pytorch.transforms import ToTensorV2\n\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\n\nfrom pathlib import Path\n","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","execution":{"iopub.status.busy":"2024-05-17T17:51:21.590245Z","iopub.execute_input":"2024-05-17T17:51:21.590582Z","iopub.status.idle":"2024-05-17T17:51:22.164040Z","shell.execute_reply.started":"2024-05-17T17:51:21.590553Z","shell.execute_reply":"2024-05-17T17:51:22.163104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load sino dataset\n","metadata":{}},{"cell_type":"code","source":"import os\nimport cv2\n\n\ndef get_custom_data_dicts(images_dir, labels_dir):\n    dataset_dicts = []\n\n    # Get list of label files\n    label_files = os.listdir(labels_dir)\n\n    for label_file in label_files:\n        # Extract image id from label file name\n        image_id = label_file.split('.')[0]\n        image_path = os.path.join(images_dir, f\"{image_id}.jpg\")\n        label_path = os.path.join(labels_dir, label_file)\n\n        # Load image to get width and height\n        img = cv2.imread(image_path)\n        height, width, _ = img.shape\n\n        # Read label file\n        with open(label_path, 'r') as f:\n            lines = f.readlines()\n\n        objs = []\n        for line in lines:\n            data = line.strip().split()\n            class_0, x_center, y_center, w, h = map(float, data)\n            \n            x_min = int((x_center - w / 2) * width)\n            y_min = int((y_center - h / 2) * height)\n            x_max = int((x_center + w / 2) * width)\n            y_max = int((y_center + h / 2) * height)\n\n            record = {\n                \"image_id\": image_id,\n                \"height\": height,\n                \"width\": width,\n                \"x_min\": x_min,\n                \"y_min\": y_min,\n                \"x_max\": x_max,\n                \"y_max\": y_max,\n            }\n\n            dataset_dicts.append(record)\n    \n    df = pd.DataFrame(dataset_dicts)\n\n    return df\n","metadata":{"execution":{"iopub.status.busy":"2024-05-17T17:51:22.166054Z","iopub.execute_input":"2024-05-17T17:51:22.166437Z","iopub.status.idle":"2024-05-17T17:51:22.179774Z","shell.execute_reply.started":"2024-05-17T17:51:22.166395Z","shell.execute_reply":"2024-05-17T17:51:22.178916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dir = \"/kaggle/input/sino-nom-dataset/wb_localization_dataset/images/train\"","metadata":{"execution":{"iopub.status.busy":"2024-05-17T17:51:22.198100Z","iopub.execute_input":"2024-05-17T17:51:22.198385Z","iopub.status.idle":"2024-05-17T17:51:22.201995Z","shell.execute_reply.started":"2024-05-17T17:51:22.198358Z","shell.execute_reply":"2024-05-17T17:51:22.201272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Path to image and label directories train\nimages_dir_train = \"/kaggle/input/sino-nom-dataset/wb_localization_dataset/images/train\"\nlabels_dir_train = \"/kaggle/input/sino-nom-dataset/wb_localization_dataset/labels/train\"\n\ndf = get_custom_data_dicts(images_dir_train, labels_dir_train)\n\ndf","metadata":{"execution":{"iopub.status.busy":"2024-05-17T17:51:22.419491Z","iopub.execute_input":"2024-05-17T17:51:22.419837Z","iopub.status.idle":"2024-05-17T17:51:23.208247Z","shell.execute_reply.started":"2024-05-17T17:51:22.419807Z","shell.execute_reply":"2024-05-17T17:51:23.207360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Helper functions","metadata":{}},{"cell_type":"code","source":"def draw_rect(img, bboxes, color=(255, 0, 0)):\n    img = img.copy()\n    for bbox in bboxes:\n        bbox = np.array(bbox).astype(int)\n        pt1, pt2 = (bbox[0], bbox[1]), (bbox[2], bbox[3])\n        img = cv2.rectangle(img, pt1, pt2, color, int(max(img.shape[:2]) / 200))\n    return img\n\ndef read_img(img_id):\n    img_path = train_dir + '/' + img_id +'.jpg'\n    img = cv2.imread(str(img_path))\n    return img\n\ndef read_bboxes(img_id):\n    return df.loc[df.image_id == img_id, 'x_min y_min x_max y_max'.split()].values\n\ndef plot_img(img_id, bbox=False):\n    img    = read_img(img_id)\n    if bbox:\n        bboxes = read_bboxes(img_id)\n        img    = draw_rect(img, bboxes)\n    plt.imshow(img);\n    \ndef plot_multiple_img(img_matrix_list, title_list, ncols, nrows=3, main_title=\"\"):\n    fig, myaxes = plt.subplots(figsize=(20, 15), nrows=nrows, ncols=ncols, squeeze=False)\n    fig.suptitle(main_title, fontsize = 30)\n    fig.subplots_adjust(wspace=0.3)\n    fig.subplots_adjust(hspace=0.3)\n    for i, (img, title) in enumerate(zip(img_matrix_list, title_list)):\n        \n        myaxes[i // ncols][i % ncols].imshow(img)\n        myaxes[i // ncols][i % ncols].set_title(title, fontsize=15)\n        myaxes[i // ncols][i % ncols].grid(False)\n        myaxes[i // ncols][i % ncols].set_xticks([])\n        myaxes[i // ncols][i % ncols].set_yticks([])\n\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-17T17:51:23.209696Z","iopub.execute_input":"2024-05-17T17:51:23.209953Z","iopub.status.idle":"2024-05-17T17:51:23.226787Z","shell.execute_reply.started":"2024-05-17T17:51:23.209928Z","shell.execute_reply":"2024-05-17T17:51:23.225936Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Test cut out 2 images:","metadata":{}},{"cell_type":"code","source":"from albumentations.augmentations.transforms import Cutout","metadata":{"execution":{"iopub.status.busy":"2024-05-17T17:51:23.950784Z","iopub.execute_input":"2024-05-17T17:51:23.951186Z","iopub.status.idle":"2024-05-17T17:51:23.955596Z","shell.execute_reply.started":"2024-05-17T17:51:23.951151Z","shell.execute_reply":"2024-05-17T17:51:23.954423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_list_chu_trang_nen_den = [\n    \"nlvnpf-0174-03-001\",\n    \"nlvnpf-0174-03-003\",\n    \"nlvnpf-0174-03-004\",\n    \"nlvnpf-0174-03-005\",\n    \"nlvnpf-0174-03-006\",\n    \"nlvnpf-0174-03-007\",\n    \"nlvnpf-0174-03-012\",\n]","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:28:23.241672Z","iopub.execute_input":"2024-05-17T18:28:23.242026Z","iopub.status.idle":"2024-05-17T18:28:23.246279Z","shell.execute_reply.started":"2024-05-17T18:28:23.241984Z","shell.execute_reply":"2024-05-17T18:28:23.245310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Xác định kích thước mới cho ảnh sau khi zoom (ví dụ: tăng gấp đôi kích thước)\nnew_width = int(chosen_img.shape[1] * 2)\nnew_height = int(chosen_img.shape[0] * 2)\nnew_size = (new_width, new_height)\n\n# Zoom ảnh bằng cách sử dụng phép biến đổi không gian mẫu\nzoomed_image = cv2.resize(chosen_img, new_size, interpolation=cv2.INTER_LINEAR)\n\n# Hiển thị ảnh\ncv2.imshow('Zoomed Image', zoomed_image)","metadata":{"execution":{"iopub.status.busy":"2024-05-17T17:49:13.423990Z","iopub.execute_input":"2024-05-17T17:49:13.424385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# define list","metadata":{}},{"cell_type":"code","source":"img_list_full_train = [\n    \"nlvnpf-0137-01-019\",\n    \"nlvnpf-0137-01-015\",\n    \"nlvnpf-0137-01-024\",\n    \"nlvnpf-0137-01-041\",\n    \"nlvnpf-0174-03-005\",\n    \"nlvnpf-0137-01-022\",\n    \"nlvnpf-0137-01-011\",\n    \"nlvnpf-0137-01-039\",\n    \"nlvnpf-0137-01-004\",\n    \"nlvnpf-0137-01-027\",\n    \"nlvnpf-0137-01-002\",\n    \"nlvnpf-0137-01-009\",\n    \"nlvnpf-0140-01-005\",\n    \"nlvnpf-0137-01-028\",\n    \"nlvnpf-0174-03-009\",\n    \"nlvnpf-0137-01-017\",\n    \"nlvnpf-0174-03-006\",\n    \"nlvnpf-0137-01-032\",\n    \"nlvnpf-0137-01-007\",\n    \"nlvnpf-0140-01-015\",\n    \"nlvnpf-0137-01-033\",\n    \"nlvnpf-0140-01-014\",\n    \"nlvnpf-0137-01-035\",\n    \"nlvnpf-0137-01-031\",\n    \"nlvnpf-0137-01-038\",\n    \"nlvnpf-0174-03-010\",\n    \"nlvnpf-0137-01-021\",\n    \"nlvnpf-0137-01-042\",\n    \"nlvnpf-0140-01-010\",\n    \"nlvnpf-0137-01-008\",\n    \"nlvnpf-0140-01-008\",\n    \"nlvnpf-0137-01-005\",\n    \"nlvnpf-0137-01-018\",\n    \"nlvnpf-0140-01-013\",\n    \"nlvnpf-0137-01-036\",\n    \"nlvnpf-0137-01-003\",\n    \"nlvnpf-0137-01-043\",\n    \"nlvnpf-0174-03-008\",\n    \"nlvnpf-0140-01-009\",\n    \"nlvnpf-0140-01-004\",\n    \"nlvnpf-0137-01-040\",\n    \"nlvnpf-0137-01-026\",\n    \"nlvnpf-0137-01-025\",\n    \"nlvnpf-0137-01-037\",\n    \"nlvnpf-0140-01-003\",\n    \"nlvnpf-0140-01-011\",\n    \"nlvnpf-0174-03-012\",\n    \"nlvnpf-0137-01-034\",\n    \"nlvnpf-0137-01-023\",\n    \"nlvnpf-0137-01-044\",\n    \"nlvnpf-0174-03-007\",\n    \"nlvnpf-0174-03-011\",\n    \"nlvnpf-0140-01-006\",\n    \"nlvnpf-0140-01-002\",\n    \"nlvnpf-0174-03-003\",\n    \"nlvnpf-0174-03-001\",\n    \"nlvnpf-0174-03-004\",\n    \"nlvnpf-0137-01-006\",\n    \"nlvnpf-0137-01-029\",\n    \"nlvnpf-0137-01-012\",\n    \"nlvnpf-0137-01-030\",\n    \"nlvnpf-0174-03-002\",\n    \"nlvnpf-0137-01-020\",\n    \"nlvnpf-0140-01-012\",\n    \"nlvnpf-0140-01-007\",\n    \"nlvnpf-0137-01-016\",\n    \"nlvnpf-0137-01-010\",\n    \"nlvnpf-0137-01-001\",\n    \"nlvnpf-0137-01-013\",\n    \"nlvnpf-0137-01-014\",\n]","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:31:19.197735Z","iopub.execute_input":"2024-05-17T18:31:19.198105Z","iopub.status.idle":"2024-05-17T18:31:19.208383Z","shell.execute_reply.started":"2024-05-17T18:31:19.198066Z","shell.execute_reply":"2024-05-17T18:31:19.207272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_list_chu_trang_nen_den = [\n    \"nlvnpf-0174-03-001\",\n    \"nlvnpf-0174-03-003\",\n    \"nlvnpf-0174-03-004\",\n    \"nlvnpf-0174-03-005\",\n    \"nlvnpf-0174-03-006\",\n    \"nlvnpf-0174-03-007\",\n    \"nlvnpf-0174-03-012\",\n]","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:31:19.798263Z","iopub.execute_input":"2024-05-17T18:31:19.798617Z","iopub.status.idle":"2024-05-17T18:31:19.803846Z","shell.execute_reply.started":"2024-05-17T18:31:19.798586Z","shell.execute_reply":"2024-05-17T18:31:19.802578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_list_chu_be = [\n    \"nlvnpf-0137-01-005\",\n    \"nlvnpf-0137-01-007\",\n    \"nlvnpf-0137-01-008\",\n    \"nlvnpf-0137-01-010\",\n    \"nlvnpf-0137-01-011\",\n    \"nlvnpf-0137-01-012\",\n    \"nlvnpf-0137-01-014\",\n    \"nlvnpf-0137-01-015\",\n    \"nlvnpf-0137-01-016\",\n    \"nlvnpf-0137-01-017\",\n    \"nlvnpf-0137-01-024\",\n    \"nlvnpf-0137-01-033\",\n    \"nlvnpf-0137-01-040\",\n    \"nlvnpf-0137-01-043\",\n    \"nlvnpf-0137-01-044\",\n    \"nlvnpf-0140-01-015\",\n    \"nlvnpf-0174-03-002\",\n    \"nlvnpf-0174-03-012\",\n]","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:31:20.080866Z","iopub.execute_input":"2024-05-17T18:31:20.081245Z","iopub.status.idle":"2024-05-17T18:31:20.086517Z","shell.execute_reply.started":"2024-05-17T18:31:20.081207Z","shell.execute_reply":"2024-05-17T18:31:20.085604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_list_chu_nhat = [\n    \"nlvnpf-0140-01-007\",\n    \"nlvnpf-0140-01-008\",\n    \"nlvnpf-0140-01-009\",\n    \"nlvnpf-0140-01-010\",\n    \"nlvnpf-0140-01-011\",\n    \"nlvnpf-0140-01-012\",\n    \"nlvnpf-0140-01-013\",\n]","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:31:20.426053Z","iopub.execute_input":"2024-05-17T18:31:20.426556Z","iopub.status.idle":"2024-05-17T18:31:20.432469Z","shell.execute_reply.started":"2024-05-17T18:31:20.426507Z","shell.execute_reply":"2024-05-17T18:31:20.431128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_list_vet_ban = [\n    \"nlvnpf-0137-01-002\",\n    \"nlvnpf-0137-01-003\",\n    \"nlvnpf-0137-01-004\",\n    \"nlvnpf-0137-01-006\",\n    \"nlvnpf-0137-01-009\",\n    \"nlvnpf-0137-01-012\",\n    \"nlvnpf-0137-01-037\",\n    \"nlvnpf-0140-01-015\",\n    \"nlvnpf-0174-03-009\",\n]","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:31:20.717490Z","iopub.execute_input":"2024-05-17T18:31:20.717826Z","iopub.status.idle":"2024-05-17T18:31:20.722627Z","shell.execute_reply.started":"2024-05-17T18:31:20.717797Z","shell.execute_reply":"2024-05-17T18:31:20.721606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TODO version: change aug_set and img_list\nimg_list = img_list_full_train\naug_set = \"full_train/\"","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:47:00.043879Z","iopub.execute_input":"2024-05-17T18:47:00.044301Z","iopub.status.idle":"2024-05-17T18:47:00.048527Z","shell.execute_reply.started":"2024-05-17T18:47:00.044259Z","shell.execute_reply":"2024-05-17T18:47:00.047518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define paths\noutput_dir_crop_images = aug_set + 'output_crop_safe/images'\noutput_dir_crop_label = aug_set + 'output_crop_safe/label'\noutput_dir_crop_double_check = aug_set + 'output_crop_safe/check'\n\n# Ensure output directories exist\nos.makedirs(output_dir_crop_images, exist_ok=True)\nos.makedirs(output_dir_crop_label, exist_ok=True)\nos.makedirs(output_dir_crop_double_check, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:46:44.498705Z","iopub.execute_input":"2024-05-17T18:46:44.499084Z","iopub.status.idle":"2024-05-17T18:46:44.505635Z","shell.execute_reply.started":"2024-05-17T18:46:44.499047Z","shell.execute_reply":"2024-05-17T18:46:44.504811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for img_id in img_list:\n    chosen_img = read_img(img_id)\n    bboxes = read_bboxes(img_id)\n   \n    bbox_params = {'format': 'pascal_voc', 'label_fields': ['labels']}\n    img_matrix_list = [chosen_img]\n    # Scale factor\n    scale_factor = 1  # Scale image by 5 times\n    \n    # Xác định kích thước mới cho ảnh sau khi zoom (scale)\n    new_width = int(chosen_img.shape[1] * scale_factor)\n    new_height = int(chosen_img.shape[0] * scale_factor)\n    zoom_out_scale_factor = 2  # Ví dụ: Zoom ảnh ra 200%\n\n    # Define the augmentation pipeline with safe cutting or zooming\n    augmentation = A.Compose([\n         A.RandomScale(scale_limit=(zoom_out_scale_factor, zoom_out_scale_factor), p=0.9),\n        A.RandomSizedBBoxSafeCrop(height=new_height, width=new_width, p=1), # height, width after cut\n        A.RandomSizedBBoxSafeCrop(height=new_height, width=new_width, p=1), # height, width after cut\n        A.RandomSizedBBoxSafeCrop(height=new_height, width=new_width, p=1), # height, width after cut\n    ], bbox_params=bbox_params)\n\n\n    # Draw original bounding boxes on the image\n    img_matrix_list = [draw_rect(chosen_img, bboxes)]\n\n    # Apply augmentation\n    anno_safe_zoom_image = augmentation(image=chosen_img, bboxes=bboxes, labels=np.ones(len(bboxes)))\n\n    # Draw bounding boxes on the augmented image\n    img = draw_rect(anno_safe_zoom_image['image'], anno_safe_zoom_image['bboxes'])\n    img_matrix_list.append(img)\n    \n    combined_img = np.vstack(img_matrix_list)  # img_matrix_list là list của các ma trận ảnh\n    cv2.imwrite(os.path.join(output_dir_crop_images, f'{img_id}_crop.jpg'), anno_safe_zoom_image['image'])\n    cv2.imwrite(os.path.join(output_dir_crop_double_check, f'{img_id}_crop.jpg'), combined_img)\n\n    # convert Pascal VOC to YOLO format and save output\n    with open(os.path.join(output_dir_crop_label, f'{img_id}_crop.txt'), 'w') as label_file:\n        img_height, img_width, _ = img.shape\n        for bbox in anno_safe_zoom_image['bboxes']:\n\n            # convert Pascal VOC to YOLO format\n            x_min, y_min, x_max, y_max = bbox\n            x_center = (x_min + x_max) / 2 / img_width\n            y_center = (y_min + y_max) / 2 / img_height\n            width = (x_max - x_min) / img_width\n            height = (y_max - y_min) / img_height\n\n            # save output\n            label_file.write(f'0 {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\\n')\n    print(\"Save images and label of\", img_id, \"successfully\")","metadata":{"execution":{"iopub.status.busy":"2024-05-17T18:48:30.561864Z","iopub.execute_input":"2024-05-17T18:48:30.562246Z","iopub.status.idle":"2024-05-17T18:48:38.401670Z","shell.execute_reply.started":"2024-05-17T18:48:30.562212Z","shell.execute_reply":"2024-05-17T18:48:38.400891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Albumentation augmentation","metadata":{}},{"cell_type":"code","source":"# Define paths\noutput_img_dir = aug_set + 'output_albu/images'\noutput_label_dir = aug_set + 'output_albu/label'\noutput_check_dir = aug_set + 'output_albu/check'\n\n# Ensure output directories exist\nos.makedirs(output_img_dir, exist_ok=True)\nos.makedirs(output_label_dir, exist_ok=True)\nos.makedirs(output_check_dir, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:44.745073Z","iopub.execute_input":"2024-05-11T15:14:44.745419Z","iopub.status.idle":"2024-05-11T15:14:44.751703Z","shell.execute_reply.started":"2024-05-11T15:14:44.745389Z","shell.execute_reply":"2024-05-11T15:14:44.750938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"bbox_params = {'format': 'pascal_voc', 'label_fields': ['labels']}\n\nalbumentation_list = [A.Compose([A.Rotate(p=1, limit=15)], bbox_params=bbox_params),\n                      A.Compose([A.InvertImg(p=1)], bbox_params=bbox_params), \n                      A.Compose([A.Blur(blur_limit=10, p=1)], bbox_params=bbox_params),\n#                       A.Compose([A.Downscale()], bbox_params=bbox_params), \n                      A.Compose([A.RandomSizedBBoxSafeCrop(height=1000, width=1000)], bbox_params=bbox_params),\n                      A.Compose([A.Resize(300,300)], bbox_params=bbox_params)]\n\ntitles_list = [\"Rotate\",\n               \"InvertImg\", \n               \"Blur\", \n#                \"Downscale\", \n               \"RamdomSizedBBoxSafeCrop\",\n               \"Resize\"]\n# TODO: randomCrop -> Crop bigsize \n\nfor img_id in img_list:\n    chosen_img = read_img(img_id)\n    bboxes = read_bboxes(img_id)\n\n    img_bbox_matrix_list = []\n    anno_img_matrix_list = []\n    anno_bbox_matrix_list = []\n\n    for i, aug_type in enumerate(albumentation_list):\n        anno = aug_type(image=chosen_img, bboxes=bboxes, labels=np.ones(len(bboxes)))\n        img  = draw_rect(anno['image'], anno['bboxes'])\n        anno_img_matrix_list.append(anno['image'])\n        anno_bbox_matrix_list.append(anno['bboxes'])\n\n        cv2.imwrite(os.path.join(output_check_dir, f'{img_id}_augcheck_{titles_list[i]}.jpg'), img)\n        cv2.imwrite(os.path.join(output_img_dir, f'{img_id}_aug_{titles_list[i]}.jpg'), anno['image'])\n\n        with open(os.path.join(output_label_dir, f'{img_id}_aug_{titles_list[i]}.txt'), 'w') as label_file:\n            img_height, img_width, _ = img.shape\n            for bbox in anno['bboxes']:\n                x_min, y_min, x_max, y_max = bbox\n                # Calculate bbox in YOLO format\n                x_center = (x_min + x_max) / 2 / img_width\n                y_center = (y_min + y_max) / 2 / img_height\n                width = (x_max - x_min) / img_width\n                height = (y_max - y_min) / img_height\n                # Write to label file\n                label_file.write(f'0 {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\\n')\n    ","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:45.017370Z","iopub.execute_input":"2024-05-11T15:14:45.017820Z","iopub.status.idle":"2024-05-11T15:14:46.599595Z","shell.execute_reply.started":"2024-05-11T15:14:45.017763Z","shell.execute_reply":"2024-05-11T15:14:46.598432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Advance Augmentations\n\nIn recent times, many new augmentation techniques have been devloped. Some of them are extremely powerful. When applied, they can help your model generalize better and make it more robust. We will look are 2 of them that we think it will improve the robustness of HandWriten Sinonom Detection: \n- CutOut\n- CutMix\n\nLets get started . . .","metadata":{}},{"cell_type":"markdown","source":"# Cutout Augmentation\n\n**CutOut** is a technique for regularizing CNN models. It works by masking square regions of the image. By randomly masking regions of the image we can prevent the model from falling prey to noice in the data and overfit. \n\n**Note:** Reading research papers is one of the most under rated skill set in Deep Learning community, but to become a good practitioner you must regularly spend time reading research papers. This [cutout paper](https://arxiv.org/pdf/1708.04552) is an easy read, give it a try.\n\nAlbumentations already has a working implementation of CutOut. So, we will use it directly. ","metadata":{}},{"cell_type":"code","source":"from albumentations.augmentations.transforms import Cutout","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:46.602131Z","iopub.execute_input":"2024-05-11T15:14:46.602559Z","iopub.status.idle":"2024-05-11T15:14:46.607436Z","shell.execute_reply.started":"2024-05-11T15:14:46.602514Z","shell.execute_reply":"2024-05-11T15:14:46.606467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_id = 'nlvnpf-0137-01-001' \nchosen_img = read_img(img_id)\nbboxes = read_bboxes(img_id)\n\nbbox_params = {'format': 'pascal_voc', 'label_fields': ['labels']}\naugmentation = A.Compose([Cutout(num_holes=5, \n                                 max_h_size=80, \n                                 max_w_size=80, \n                                 fill_value=0, \n                                 p=1),\n                         ], \n                         bbox_params=bbox_params)\n\nimg_matrix_list = [draw_rect(chosen_img, bboxes)]\n\nanno = augmentation(image=chosen_img, bboxes=bboxes, labels=np.ones(len(bboxes)))\nimg  = draw_rect(anno['image'], anno['bboxes'])\nimg_matrix_list.append(img)\n\ntitles_list = [\"Original\", \"CutOut\"]\n\nplot_multiple_img(img_matrix_list, titles_list, ncols = 2, nrows= 1, main_title=\"\")","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:46.609150Z","iopub.execute_input":"2024-05-11T15:14:46.609591Z","iopub.status.idle":"2024-05-11T15:14:46.939838Z","shell.execute_reply.started":"2024-05-11T15:14:46.609544Z","shell.execute_reply":"2024-05-11T15:14:46.938744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There is one problem with this, if you make the `max_h_size` and `max_w_size` very high, say 250 px. Then you will have some bounding boxes inside the patch. This is what I am talking about. \nThis makes it really difficult for the model to learn from the images. Ideally, we should also remove the bounding boxes that lies inside the mask. So, I would recommend you to use it with small values of `max_h_size` and `max_w_size`. \n\n**Note:** All the data augmentation techniques that we have use so far can be applied to any type of computer vision problem. From here on, the code can only be used for object detection.","metadata":{}},{"cell_type":"code","source":"from albumentations.core.transforms_interface import DualTransform\nfrom albumentations.augmentations.bbox_utils import denormalize_bbox, normalize_bbox\n\nclass CustomCutout(DualTransform):\n    \"\"\"\n    Custom Cutout augmentation with handling of bounding boxes \n    Note: (only supports square cutout regions)\n    \n    Author: Kaushal28\n    Reference: https://arxiv.org/pdf/1708.04552.pdf\n    \"\"\"\n    \n    def __init__(\n        self,\n        fill_value=0,\n        bbox_removal_threshold=0.50,\n        min_cutout_size=192,\n        max_cutout_size=512,\n        always_apply=False,\n        p=0.5\n    ):\n        \"\"\"\n        Class construstor\n        \n        :param fill_value: Value to be filled in cutout (default is 0 or black color)\n        :param bbox_removal_threshold: Bboxes having content cut by cutout path more than this threshold will be removed\n        :param min_cutout_size: minimum size of cutout (192 x 192)\n        :param max_cutout_size: maximum size of cutout (512 x 512)\n        \"\"\"\n        super(CustomCutout, self).__init__(always_apply, p)  # Initialize parent class\n        self.fill_value = fill_value\n        self.bbox_removal_threshold = bbox_removal_threshold\n        self.min_cutout_size = min_cutout_size\n        self.max_cutout_size = max_cutout_size\n        \n    def _get_cutout_position(self, img_height, img_width, cutout_size):\n        \"\"\"\n        Randomly generates cutout position as a named tuple\n        \n        :param img_height: height of the original image\n        :param img_width: width of the original image\n        :param cutout_size: size of the cutout patch (square)\n        :returns position of cutout patch as a named tuple\n        \"\"\"\n        position = namedtuple('Point', 'x y')\n        return position(\n            np.random.randint(0, img_width - cutout_size + 1),\n            np.random.randint(0, img_height - cutout_size + 1)\n        )\n        \n    def _get_cutout(self, img_height, img_width):\n        \"\"\"\n        Creates a cutout pacth with given fill value and determines the position in the original image\n        \n        :param img_height: height of the original image\n        :param img_width: width of the original image\n        :returns (cutout patch, cutout size, cutout position)\n        \"\"\"\n        cutout_size = np.random.randint(self.min_cutout_size, self.max_cutout_size + 1)\n        cutout_position = self._get_cutout_position(img_height, img_width, cutout_size)\n        return np.full((cutout_size, cutout_size, 3), self.fill_value), cutout_size, cutout_position\n        \n    def apply(self, image, **params):\n        \"\"\"\n        Applies the cutout augmentation on the given image\n        \n        :param image: The image to be augmented\n        :returns augmented image\n        \"\"\"\n        image = image.copy()  # Don't change the original image\n        self.img_height, self.img_width, _ = image.shape\n        cutout_arr, cutout_size, cutout_pos = self._get_cutout(self.img_height, self.img_width)\n        \n        # Set to instance variables to use this later\n        self.image = image\n        self.cutout_pos = cutout_pos\n        self.cutout_size = cutout_size\n        \n        image[cutout_pos.y:cutout_pos.y+cutout_size, cutout_pos.x:cutout_size+cutout_pos.x, :] = cutout_arr\n        return image\n    \n    def apply_to_bbox(self, bbox, **params):\n        \"\"\"\n        Removes the bounding boxes which are covered by the applied cutout\n        \n        :param bbox: A single bounding box coordinates in pascal_voc format\n        :returns transformed bbox's coordinates\n        \"\"\"\n\n        # Denormalize the bbox coordinates\n        bbox = denormalize_bbox(bbox, self.img_height, self.img_width)\n        x_min, y_min, x_max, y_max = tuple(map(int, bbox))\n\n        bbox_size = (x_max - x_min) * (y_max - y_min)  # width * height\n        overlapping_size = np.sum(\n            (self.image[y_min:y_max, x_min:x_max, 0] == self.fill_value) &\n            (self.image[y_min:y_max, x_min:x_max, 1] == self.fill_value) &\n            (self.image[y_min:y_max, x_min:x_max, 2] == self.fill_value)\n        )\n\n        # Remove the bbox if it has more than some threshold of content is inside the cutout patch\n        if overlapping_size / bbox_size > self.bbox_removal_threshold:\n            return normalize_bbox((0, 0, 0, 0), self.img_height, self.img_width)\n\n        return normalize_bbox(bbox, self.img_height, self.img_width)\n\n    def get_transform_init_args_names(self):\n        \"\"\"\n        Fetches the parameter(s) of __init__ method\n        :returns: tuple of parameter(s) of __init__ method\n        \"\"\"\n        return ('fill_value', 'bbox_removal_threshold', 'min_cutout_size', 'max_cutout_size', 'always_apply', 'p')","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:46.941632Z","iopub.execute_input":"2024-05-11T15:14:46.942015Z","iopub.status.idle":"2024-05-11T15:14:46.966017Z","shell.execute_reply.started":"2024-05-11T15:14:46.941977Z","shell.execute_reply":"2024-05-11T15:14:46.965248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport os\n\n# Đường dẫn đến thư mục lưu hình ảnh và tập tin nhãn\noutput_dir_cutout_label = aug_set + 'output_cutout/label'\noutput_dir_cutout_images = aug_set + 'output_cutout/images'\noutput_dir_cutout_double_check = aug_set + 'output_cutout/check'\nos.makedirs(output_dir_cutout_label, exist_ok=True)\nos.makedirs(output_dir_cutout_images, exist_ok=True)\nos.makedirs(output_dir_cutout_double_check, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:46.968451Z","iopub.execute_input":"2024-05-11T15:14:46.968727Z","iopub.status.idle":"2024-05-11T15:14:46.980868Z","shell.execute_reply.started":"2024-05-11T15:14:46.968699Z","shell.execute_reply":"2024-05-11T15:14:46.980194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nfor img_id in img_list:\n    chosen_img = read_img(img_id)\n    bboxes = read_bboxes(img_id)\n\n    bbox_params = {'format': 'pascal_voc', 'label_fields': ['labels']}\n    augmentation = A.Compose([CustomCutout(p=1),], bbox_params = bbox_params)\n\n    img_matrix_list = [draw_rect(chosen_img, bboxes)]\n\n    anno = augmentation(image=chosen_img, bboxes=bboxes, labels=np.ones(len(bboxes)))\n    img  = draw_rect(anno['image'], anno['bboxes'])\n    img_matrix_list.append(img)\n    \n    combined_img = np.vstack(img_matrix_list) \n    \n    # SAVE AUGMENTED IMAGE AND LABEL \n    cv2.imwrite(os.path.join(output_dir_cutout_images, f'{img_id}_aug_cutout.jpg'), anno['image'])\n    cv2.imwrite(os.path.join(output_dir_cutout_double_check, f'{img_id}_aug_cutout_check.jpg'), combined_img)\n\n    # convert Pascal VOC to YOLO format and save output\n    with open(os.path.join(output_dir_cutout_label, f'{img_id}_aug_cutout.txt'), 'w') as label_file:\n        img_height, img_width, _ = img.shape\n        for bbox in anno['bboxes']:\n             # convert Pascal VOC to YOLO format\n            x_min, y_min, x_max, y_max = bbox\n            x_center = (x_min + x_max) / 2 / img_width\n            y_center = (y_min + y_max) / 2 / img_height\n            width = (x_max - x_min) / img_width\n            height = (y_max - y_min) / img_height\n\n            # save output\n            label_file.write(f'0 {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\\n')\n    print(\"Save images and label of\", img_id, \"successfully\")","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:46.982434Z","iopub.execute_input":"2024-05-11T15:14:46.982711Z","iopub.status.idle":"2024-05-11T15:14:47.063889Z","shell.execute_reply.started":"2024-05-11T15:14:46.982684Z","shell.execute_reply":"2024-05-11T15:14:47.063063Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# CutMix Augmentation\n","metadata":{}},{"cell_type":"code","source":"def rand_bbox(size, lamb):\n    \"\"\" Generate random bounding box \n    Args:\n        - size: [width, breadth] of the bounding box\n        - lamb: (lambda) cut ratio parameter\n    Returns:\n        - Bounding box\n    \"\"\"\n    W = size[0]\n    H = size[1]\n    cut_rat = np.sqrt(1. - lamb)\n    cut_w = np.int(W * cut_rat)\n    cut_h = np.int(H * cut_rat)\n\n    # uniform\n    cx = np.random.randint(W)\n    cy = np.random.randint(H)\n\n    bbx1 = np.clip(cx - cut_w // 2, 0, W)\n    bby1 = np.clip(cy - cut_h // 2, 0, H)\n    bbx2 = np.clip(cx + cut_w // 2, 0, W)\n    bby2 = np.clip(cy + cut_h // 2, 0, H)\n\n    return bbx1, bby1, bbx2, bby2\n\n\ndef generate_cutmix_image(images, bboxes, beta=1.0, th=0.25):\n    \"\"\" Generate a CutMix augmented image from a batch \n    Args:\n        - image_batch: a batch of input images\n        - image_batch_labels: labels corresponding to the image batch\n        - beta: a parameter of Beta distribution.\n    Returns:\n        - CutMix image batch, updated labels\n    \"\"\"\n    # generate mixed sample\n    fill_value = 255\n    lam = np.random.beta(beta, beta)\n    target_a = bboxes[0]\n    target_b = bboxes[1]\n    w, h, c = images[0].shape\n    bbx1, bby1, bbx2, bby2 = rand_bbox((w,h,c), lam)\n    cutmix_image = images[0].copy()\n    cutmix_image[bby1:bby2, bbx1:bbx2, :] = fill_value\n    \n    # bboxes\n    new_bboxes = []\n    for bbox in bboxes[0]:\n        x_min, y_min, x_max, y_max = map(int, bbox)\n    \n        bbox_size = (x_max - x_min) * (y_max - y_min)  # width * height\n        overlapping_size = np.sum(\n            (cutmix_image[y_min:y_max, x_min:x_max, 0] == fill_value) &\n            (cutmix_image[y_min:y_max, x_min:x_max, 1] == fill_value) &\n            (cutmix_image[y_min:y_max, x_min:x_max, 2] == fill_value)\n        )\n\n        # Add the bbox if it has less than some threshold of content is inside the cutout patch\n        if overlapping_size / bbox_size < th:\n            new_bboxes.append(bbox)\n            \n    mask = np.zeros(images[1].shape)\n    mask[bby1:bby2, bbx1:bbx2, :] = 1\n    image2 = images[1]*mask\n    \n    for bbox in bboxes[1]:\n        x_min, y_min, x_max, y_max = map(int, bbox)\n    \n        bbox_size = (x_max - x_min) * (y_max - y_min)  # width * height\n        overlapping_size = np.sum(\n            (image2[y_min:y_max, x_min:x_max, 0] == 0) &\n            (image2[y_min:y_max, x_min:x_max, 1] == 0) &\n            (image2[y_min:y_max, x_min:x_max, 2] == 0)\n        )\n\n        # Add the bbox if it has less than some threshold of content is inside the cutout patch\n        if overlapping_size / bbox_size < th:\n            new_bboxes.append(bbox)\n    \n    cutmix_image[bby1:bby2, bbx1:bbx2, :] = image2[bby1:bby2, bbx1:bbx2, :]\n        \n    return cutmix_image, new_bboxes","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:47.332593Z","iopub.execute_input":"2024-05-11T15:14:47.332939Z","iopub.status.idle":"2024-05-11T15:14:47.355852Z","shell.execute_reply.started":"2024-05-11T15:14:47.332897Z","shell.execute_reply":"2024-05-11T15:14:47.354842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Đường dẫn đến thư mục lưu hình ảnh và tập tin nhãn\noutput_dir_cutmix_label = aug_set + 'output_cutmix/label'\noutput_dir_cutmix_images = aug_set + 'output_cutmix/images'\noutput_dir_cutmix_double_check = aug_set + 'output_cutmix/check'\nos.makedirs(output_dir_cutmix_label, exist_ok=True)\nos.makedirs(output_dir_cutmix_images, exist_ok=True)\nos.makedirs(output_dir_cutmix_double_check, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:14:47.631796Z","iopub.execute_input":"2024-05-11T15:14:47.632137Z","iopub.status.idle":"2024-05-11T15:14:47.638092Z","shell.execute_reply.started":"2024-05-11T15:14:47.632107Z","shell.execute_reply":"2024-05-11T15:14:47.637236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\nfrom itertools import combinations\n\ndef generate_image_combinations(img_list):\n    '''\n        # input: \n        img_list = ['nlvnpf-0137-01-001', 'nlvnpf-0137-01-003', 'nlvnpf-0137-01-004']\n\n        # output: is combine 2 of images in img_list\n        image_ids_list = [\n            ['nlvnpf-0137-01-001', 'nlvnpf-0137-01-003'],\n            ['nlvnpf-0137-01-001', 'nlvnpf-0137-01-004'],    \n            ['nlvnpf-0137-01-003', 'nlvnpf-0137-01-004'],\n        ]\n    '''\n    # Generate combinations of 2 images from img_list\n    image_combinations = list(combinations(img_list, 2))\n    \n    # Convert combinations to a list of lists\n    image_ids_list = [list(comb) for comb in image_combinations]\n    \n    return image_ids_list\n\n\nimage_ids_list = generate_image_combinations(img_list)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_image_height_width(image_id):\n    # Load the image using cv2\n    img = cv2.imread(image_id)  # Assuming image_id is the file path\n    \n    # Get the height and width of the image\n    height, width, _ = img.shape\n    \n    return height, width","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for image_ids in image_ids_list:\n#     if len(image_ids) != 2:\n#         print(f\"Skipping {image_ids} because it doesn't have exactly 2 elements\")\n#         continue\n    \n#     # Get the height and width of the first image\n#     img1_height, img1_width = get_image_height_width(image_ids[0])\n    \n#     # Get the height and width of the second image\n#     img2_height, img2_width = get_image_height_width(image_ids[1])\n    \n#     # Check if the height and width of both images are the same\n#     if img1_height != img2_height or img1_width != img2_width:\n#         print(f\"Skipping {image_ids} because the images have different sizes\")\n#         continue\n    try:\n        images = [read_img(img_id)    for img_id in image_ids]\n        bboxes = [read_bboxes(img_id) for img_id in image_ids]\n\n        aug_image, aug_bbox = generate_cutmix_image(images, bboxes)\n\n        images += [aug_image]\n        bboxes += [aug_bbox]\n\n        img_matrix_list = []\n        for img, bbox in zip(images, bboxes): \n            img_matrix_list.append(draw_rect(img, bbox))\n\n        titles_list     = ['Image 1', 'Image 2', 'Augmented Image']\n        plot_multiple_img(img_matrix_list, titles_list, ncols = 3, nrows= 1, main_title=\"\")\n\n        # SAVE AUGMENTED IMAGE AND LABEL \n        img_id = '_'.join(image_ids)\n        combined_img = np.vstack(img_matrix_list)  # img_matrix_list là list của các ma trận ảnh\n        cv2.imwrite(os.path.join(output_dir_cutmix_images, f'{img_id}_cutmix.jpg'), aug_image)\n        cv2.imwrite(os.path.join(output_dir_cutmix_double_check, f'{img_id}_cutmix_1_2_aug.jpg'), combined_img)\n\n        # convert Pascal VOC to YOLO format and save output\n        with open(os.path.join(output_dir_cutmix_label, f'{img_id}_cutmix.txt'), 'w') as label_file:\n            img_height, img_width, _ = img.shape\n            for bbox in aug_bbox:\n\n                # convert Pascal VOC to YOLO format\n                x_min, y_min, x_max, y_max = bbox\n                x_center = (x_min + x_max) / 2 / img_width\n                y_center = (y_min + y_max) / 2 / img_height\n                width = (x_max - x_min) / img_width\n                height = (y_max - y_min) / img_height\n\n                # save output\n                label_file.write(f'0 {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\\n')\n        print(\"Save images and label of\", img_id, \"successfully\")\n    except:\n        print(\"Incompatible shape in \", image_ids)","metadata":{"execution":{"iopub.status.busy":"2024-05-11T15:33:24.724890Z","iopub.execute_input":"2024-05-11T15:33:24.725224Z","iopub.status.idle":"2024-05-11T15:33:24.771283Z","shell.execute_reply.started":"2024-05-11T15:33:24.725197Z","shell.execute_reply":"2024-05-11T15:33:24.770212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}