From 009509b08b16d1bbd7010b73f4f9109824af6c6b Mon Sep 17 00:00:00 2001 From: insigh1 Date: Wed, 27 Dec 2023 10:38:31 -0500 Subject: [PATCH] added data_skew_solution_preprocess_augmentation_script.ipynb --- ...ution_preprocess_augmentation_script.ipynb | 685 ++++++++++++++++++ 1 file changed, 685 insertions(+) create mode 100644 notebooks/data_skew_solution_preprocess_augmentation_script.ipynb diff --git a/notebooks/data_skew_solution_preprocess_augmentation_script.ipynb b/notebooks/data_skew_solution_preprocess_augmentation_script.ipynb new file mode 100644 index 0000000..7f8d725 --- /dev/null +++ b/notebooks/data_skew_solution_preprocess_augmentation_script.ipynb @@ -0,0 +1,685 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "source": [ + "# reset files\n", + "!rm -rf datasets" + ], + "metadata": { + "id": "-yLktEgKTAgt" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Data skew fix preprocess and augmentation script\n", + "This script is an attempt to improve a skewed dataset from your Roboflow workspace with underrepresented classes. It does this by downloading the dataset images and creating new images of individual class labels with augmentations. It finds the count of each class as well as how many augmentations per class are needed to balance the dataset. After these are created, the new images are sent back to your original dataset.\n", + "\n", + "### To use this script:\n", + "This was tested on Google Colab. Simply install the libraries, then run the main cell which will ask for your:\n", + "- roboflow apikey\n", + "- roboflow workspace\n", + "- roboflow project\n", + "- roboflow project version\n", + "- roboflow download format\n", + "- desired padding around the bounding box here (in pixels)" + ], + "metadata": { + "id": "CRoq84zaCAwl" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3Ic4OxPgtPKR", + "outputId": "8f5c8276-f5fb-4b74-d32b-5fa0186292ed" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "Reading package lists... Done\n", + "Building dependency tree... Done\n", + "Reading state information... Done\n", + "tree is already the newest version (2.0.2-1).\n", + "0 upgraded, 0 newly installed, 0 to remove and 24 not upgraded.\n" + ] + } + ], + "source": [ + "!pip install --upgrade pip -q\n", + "!pip install fastapi -q\n", + "!pip install kaleido -q\n", + "!pip install uvicorn -q\n", + "!pip install python-multipart -q\n", + "!pip install roboflow -q\n", + "!pip install ultralytics==8.0.196 -q\n", + "!pip install inference -q\n", + "!pip install albumentations -q\n", + "!apt-get install tree\n" + ] + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "import ast\n", + "import glob\n", + "import albumentations as A\n", + "from tqdm import tqdm\n", + "from roboflow import Roboflow\n", + "import getpass\n", + "import requests\n", + "from io import BytesIO\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.image as mpimg\n", + "import tempfile\n", + "import cv2\n", + "import json\n", + "import math\n", + "from google.colab.patches import cv2_imshow\n", + "from ipywidgets import Video\n", + "import supervision as sv\n", + "\n", + "from IPython import display\n", + "display.clear_output()\n", + "\n", + "import ultralytics\n", + "ultralytics.checks()\n", + "\n", + "from ultralytics import YOLO\n", + "from IPython.display import display, Image\n", + "\n", + "HOME = os.getcwd()\n", + "print(HOME)\n", + "\n", + "!mkdir {HOME}/datasets\n", + "%cd {HOME}/datasets\n", + "\n", + "roboflow_apikey = getpass.getpass('enter roboflow apikey here')\n", + "roboflow_workspace = getpass.getpass('enter roboflow workspace here')\n", + "roboflow_project = getpass.getpass('enter roboflow project here')\n", + "roboflow_project_version = getpass.getpass('enter roboflow project version here')\n", + "roboflow_download_format = getpass.getpass('enter roboflow download format here')\n", + "masked_image_padding = int(getpass.getpass('enter desired padding around the bounding box here. 50 is a good start'))\n", + "\n", + "# download images and bboxes\n", + "rf = Roboflow(api_key=roboflow_apikey)\n", + "project = rf.workspace(roboflow_workspace).project(roboflow_project)\n", + "dataset = project.version(roboflow_project_version).download(roboflow_download_format)\n", + "\n", + "project_path= f'{HOME}/datasets/{roboflow_project}-{roboflow_project_version}'\n", + "original_image_path = f'{project_path}/train/images/'\n", + "original_labels_path = f'{project_path}/train/labels/'\n", + "masked_image_output_path = f'{project_path}/train/output/'\n", + "upload_path = f'{project_path}/train/upload'\n", + "yaml_file_path = f'{project_path}/data.yaml'\n", + "file_extension_type = \".jpg\"\n", + "\n", + "\n", + "# Initialize an empty list to store the class names\n", + "class_names = []\n", + "\n", + "# Reading the YAML file\n", + "with open(yaml_file_path, 'r') as file:\n", + " lines = file.readlines()\n", + " capture = False\n", + " for line in lines:\n", + " if line.strip() == \"names:\":\n", + " capture = True\n", + " continue\n", + " if line.strip().startswith('nc:'):\n", + " break\n", + " if capture:\n", + " class_names.append(line.strip().replace('- ', ''))\n", + "\n", + "# Writing to label_maps.txt in the same directory\n", + "label_maps_path = os.path.join(os.path.dirname(yaml_file_path), 'label_maps.txt')\n", + "with open(label_maps_path, 'w') as file:\n", + " for name in class_names:\n", + " file.write(name + '\\n')\n", + "\n", + "# Outputting the location of label_maps.txt\n", + "print(f\"\\n\\nClass names written to {label_maps_path}\\n\\n\")\n", + "\n", + "# Reading and displaying the contents of label_maps.txt\n", + "with open(label_maps_path, 'r') as file:\n", + " contents = file.read()\n", + " print(\"Contents of label_maps.txt:\\n\")\n", + " print(contents)\n", + "\n", + "\n", + "# saves images with padding on the mask as well as the original labels for all underrepresented classes.\n", + "# also store factor for underrepresented class with unique identifier\n", + "\n", + "# Ensure the output base path exists\n", + "if not os.path.exists(masked_image_output_path):\n", + " os.makedirs(masked_image_output_path)\n", + "\n", + "# First, count labels for each class\n", + "class_counter = {}\n", + "label_files = [f for f in os.listdir(original_labels_path) if os.path.isfile(os.path.join(original_labels_path, f))]\n", + "\n", + "for label_file in label_files:\n", + " label_file_path = os.path.join(original_labels_path, label_file)\n", + " load_bboxes = np.genfromtxt(label_file_path, dtype='float')\n", + " if load_bboxes.ndim == 1:\n", + " load_bboxes = [load_bboxes]\n", + " for bbox in load_bboxes:\n", + " category = int(bbox[0])\n", + " class_counter[category] = class_counter.get(category, 0) + 1\n", + "\n", + "# Find the maximum count\n", + "max_count = max(class_counter.values())\n", + "\n", + "# Calculate the factor for each underrepresented class\n", + "underrepresented_factors = {}\n", + "for category, count in class_counter.items():\n", + " if count < max_count:\n", + " underrepresented_factors[category] = math.floor(max_count / count)\n", + "\n", + "\n", + "# Process and save images and labels for underrepresented classes\n", + "image_files = [f for f in os.listdir(original_image_path) if os.path.isfile(os.path.join(original_image_path, f))]\n", + "\n", + "for image_file in image_files:\n", + " image_path = os.path.join(original_image_path, image_file)\n", + " label_file = image_file.replace('.jpg', '.txt')\n", + " label_file_path = os.path.join(original_labels_path, label_file)\n", + "\n", + " image = cv2.imread(image_path)\n", + " load_bboxes = np.genfromtxt(label_file_path, dtype='float')\n", + " if load_bboxes.ndim == 1:\n", + " load_bboxes = [load_bboxes]\n", + " load_bboxes = list(load_bboxes)\n", + "\n", + " img_ht, img_wd = image.shape[:2]\n", + " bbox_count = {} # Keep track of the number of bboxes for each class in this image\n", + "\n", + " for bbox in load_bboxes:\n", + " category = int(bbox[0])\n", + "\n", + " # Only process if this category's count is less than max_count\n", + " if class_counter[category] < max_count:\n", + " bbox_count[category] = bbox_count.get(category, 0) + 1\n", + " bb_width = int(round(bbox[3] * img_wd))\n", + " bb_height = int(round(bbox[4] * img_ht))\n", + "\n", + " x_center = bbox[1] * img_wd\n", + " y_center = bbox[2] * img_ht\n", + " x_min = int(x_center - (bb_width / 2))\n", + " x_max = int(x_center + (bb_width / 2))\n", + " y_min = int(y_center - (bb_height / 2))\n", + " y_max = int(y_center + (bb_height / 2))\n", + "\n", + " padded_x_min = max(x_min - masked_image_padding, 0)\n", + " padded_x_max = min(x_max + masked_image_padding, img_wd)\n", + " padded_y_min = max(y_min - masked_image_padding, 0)\n", + " padded_y_max = min(y_max + masked_image_padding, img_ht)\n", + "\n", + " mask = np.zeros(image.shape[:2], dtype=np.uint8)\n", + " cv2.rectangle(mask, (padded_x_min, padded_y_min), (padded_x_max, padded_y_max), 255, -1)\n", + " masked_image = cv2.bitwise_and(image, image, mask=mask)\n", + "\n", + " class_images_dir = os.path.join(masked_image_output_path, f'class_{category}', 'images')\n", + " class_labels_dir = os.path.join(masked_image_output_path, f'class_{category}', 'labels')\n", + " if not os.path.exists(class_images_dir):\n", + " os.makedirs(class_images_dir)\n", + " if not os.path.exists(class_labels_dir):\n", + " os.makedirs(class_labels_dir)\n", + "\n", + " base_filename = os.path.splitext(image_file)[0]\n", + " unique_identifier = f\"{base_filename}_class_{category}_{bbox_count[category]}\"\n", + " new_image_name = f'{unique_identifier}_masked.jpg'\n", + " new_label_name = f'{unique_identifier}_masked.txt'\n", + "\n", + " cv2.imwrite(os.path.join(class_images_dir, new_image_name), masked_image)\n", + " with open(os.path.join(class_labels_dir, new_label_name), 'w') as label_file:\n", + " label_file.write(f'{category} {bbox[1]} {bbox[2]} {bbox[3]} {bbox[4]}\\n')\n", + "\n", + "# Convert to JSON string with indentation\n", + "formatted_class_counts = json.dumps(class_counter, indent=4)\n", + "formatted_underrepresented_class_factors = json.dumps(underrepresented_factors, indent=4)\n", + "\n", + "# Print formatted JSON\n", + "print(\"Class Counts:\\n\", formatted_class_counts)\n", + "print(\"\\nUnderrepresented Class Factors:\\n\", formatted_underrepresented_class_factors)\n", + "\n", + "\n", + "# add augmentations to underrepresented class images using the factor of each class. Then store new images and labels in an upload folder\n", + "# Augmentations in Albumentations library need to be in Pascal_voc format so conversion needs to be done here\n", + "\n", + "# Define the Albumentations augmentation pipeline\n", + "aug = A.Compose([\n", + " A.HorizontalFlip(p=0.5),\n", + " A.RandomBrightnessContrast(brightness_limit=0.1, contrast_limit=0.1, p=0.5),\n", + " A.ShiftScaleRotate(shift_limit=0.15, scale_limit=0.15, rotate_limit=.15, p=1),\n", + " A.PadIfNeeded(min_height=1024, min_width=1024, border_mode=0, p=1.0)\n", + "], bbox_params=A.BboxParams(format='pascal_voc', label_fields=['class_labels']))\n", + "\n", + "# Function to convert YOLO format bbox to Pascal VOC format\n", + "def yolo_to_pascal_voc(bbox, img_width, img_height):\n", + " x_center, y_center, w, h = bbox\n", + " x_min = int((x_center - w / 2) * img_width)\n", + " y_min = int((y_center - h / 2) * img_height)\n", + " x_max = int((x_center + w / 2) * img_width)\n", + " y_max = int((y_center + h / 2) * img_height)\n", + " return [x_min, y_min, x_max, y_max]\n", + "\n", + "# Function to convert Pascal VOC format bbox to YOLO format\n", + "def pascal_voc_to_yolo(bbox, img_width, img_height):\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", + " w = (x_max - x_min) / img_width\n", + " h = (y_max - y_min) / img_height\n", + " return [x_center, y_center, w, h]\n", + "\n", + "# Define the output and upload paths. Remember the output folder is what is holding the padded single label images with mask.\n", + "upload_images_path = os.path.join(upload_path, 'images')\n", + "upload_labels_path = os.path.join(upload_path, 'labels')\n", + "\n", + "os.makedirs(upload_images_path, exist_ok=True)\n", + "os.makedirs(upload_labels_path, exist_ok=True)\n", + "\n", + "# underrepresented_factors is defined in previous code block\n", + "\n", + "# Iterate over each class folder in the output directory\n", + "for class_folder in os.listdir(masked_image_output_path):\n", + " class_id = int(class_folder.split('_')[1])\n", + " class_dir = os.path.join(masked_image_output_path, class_folder)\n", + " images_dir = os.path.join(class_dir, 'images')\n", + " labels_dir = os.path.join(class_dir, 'labels')\n", + "\n", + " if class_id in underrepresented_factors:\n", + " factor = underrepresented_factors[class_id]\n", + "\n", + " for image_file in os.listdir(images_dir):\n", + " image_path = os.path.join(images_dir, image_file)\n", + " label_file = image_file.replace('.jpg', '.txt')\n", + " label_path = os.path.join(labels_dir, label_file)\n", + "\n", + " # Check if label file exists and is not empty\n", + " if os.path.exists(label_path) and os.path.getsize(label_path) > 0:\n", + " image = cv2.imread(image_path)\n", + " labels = np.genfromtxt(label_path, dtype='float')\n", + " if labels.ndim == 1:\n", + " labels = [labels]\n", + "\n", + " img_ht, img_wd = image.shape[:2]\n", + " pascal_voc_bboxes = [yolo_to_pascal_voc(label[1:], img_wd, img_ht) for label in labels]\n", + " class_labels = [int(label[0]) for label in labels]\n", + "\n", + " for i in range(factor):\n", + " augmented = aug(image=image, bboxes=pascal_voc_bboxes, class_labels=class_labels)\n", + "\n", + " augmented_image_path = os.path.join(upload_images_path, f\"{os.path.splitext(image_file)[0]}_aug_{i}.jpg\")\n", + " cv2.imwrite(augmented_image_path, augmented['image'])\n", + "\n", + " augmented_label_path = os.path.join(upload_labels_path, f\"{os.path.splitext(label_file)[0]}_aug_{i}.txt\")\n", + " with open(augmented_label_path, 'w') as file:\n", + " for bbox, class_label in zip(augmented['bboxes'], augmented['class_labels']):\n", + " yolo_bbox = pascal_voc_to_yolo(bbox, img_wd, img_ht)\n", + " file.write(f\"{class_label} {' '.join(map(str, yolo_bbox))}\\n\")\n", + " else:\n", + " print(f\"Label file {label_path} is empty or does not exist.\")\n", + "\n", + "\n", + "# run through all new images with bboxes, and delete files where label doesn't exist.\n", + "# This can happen if the image moves offscreen and we don't need those files\n", + "\n", + "\n", + "# Paths for images and labels within the class directory\n", + "images_path = os.path.join(upload_path, 'images')\n", + "labels_path = os.path.join(upload_path, 'labels')\n", + "\n", + "# List to store the names of deleted files\n", + "deleted_files = []\n", + "\n", + "# Loop through each image file in the class directory\n", + "for image_file in os.listdir(images_path):\n", + " # Construct the full image and label paths\n", + " image_path = os.path.join(images_path, image_file)\n", + " label_file = image_file.replace('.jpg', '.txt')\n", + " label_file_path = os.path.join(labels_path, label_file)\n", + "\n", + " # Load the image\n", + " image = cv2.imread(image_path)\n", + "\n", + " # Check if the label file exists and is not empty\n", + " if os.path.isfile(label_file_path) and os.path.getsize(label_file_path) > 0:\n", + " pass\n", + "\n", + " else:\n", + " # Delete the image and label file and add to the deleted files list\n", + " os.remove(image_path)\n", + " deleted_files.append(image_path)\n", + " if os.path.isfile(label_file_path):\n", + " os.remove(label_file_path)\n", + " deleted_files.append(label_file_path)\n", + "\n", + "# Output the list of deleted files at the end of the script\n", + "print(\"Files deleted where label does not exist:\")\n", + "for file in deleted_files:\n", + " print(file)\n", + "\n", + "\n", + "# number of new images to upload\n", + "\n", + "# Count the .jpg files\n", + "jpg_count = sum(1 for file in os.listdir(images_path) if file.endswith('.jpg'))\n", + "\n", + "print(f\"\\n\\nNumber of .jpg files to upload: {jpg_count}\\n\\n\")\n", + "\n", + "# Upload images and corresponding annotations\n", + "image_glob = glob.glob(images_path + '/*' + file_extension_type)\n", + "for image_path in image_glob:\n", + " # Split the path and extract the filename\n", + " filename_with_extension = image_path.split('/')[-1]\n", + "\n", + " # Remove the file extension\n", + " base_name = filename_with_extension.rsplit('.', 1)[0]\n", + "\n", + " # Find all possible matching annotation files\n", + " annotation_glob = glob.glob(f\"{upload_path}/labels/{base_name}.txt\")\n", + " annotation_file = None\n", + " for potential_annotation in annotation_glob:\n", + " if base_name in potential_annotation:\n", + " annotation_file = potential_annotation\n", + " break\n", + "\n", + " if annotation_file:\n", + " # Upload image and annotation\n", + " print(project.single_upload(\n", + " image_path=image_path,\n", + " annotation_path=annotation_file,\n", + " # optional parameters:\n", + " annotation_labelmap=label_maps_path,\n", + " # split='train',\n", + " # num_retry_uploads=0,\n", + " # batch_name='batch_name',\n", + " # tag_names=['tag1', 'tag2'],\n", + " # is_prediction=False,\n", + " ))\n", + " else:\n", + " print(f\"No matching annotation file found for {image_path}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "iWaKjhwAtTC-", + "outputId": "e4c6382b-b1e9-45ef-c91d-299fcbdde5c2" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "Ultralytics YOLOv8.0.196 ๐Ÿš€ Python-3.10.12 torch-2.1.0+cu121 CPU (Intel Xeon 2.20GHz)\n", + "Setup complete โœ… (2 CPUs, 12.7 GB RAM, 26.8/107.7 GB disk)\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "/content\n", + "/content/datasets\n", + "enter roboflow apikey hereยทยทยทยทยทยทยทยทยทยท\n", + "enter roboflow workspace hereยทยทยทยทยทยทยทยทยทยท\n", + "enter roboflow project hereยทยทยทยทยทยทยทยทยทยท\n", + "enter roboflow project version hereยทยทยทยทยทยทยทยทยทยท\n", + "enter roboflow download format hereยทยทยทยทยทยทยทยทยทยท\n", + "enter desired padding around the bounding box here. 50 is a good startยทยทยทยทยทยทยทยทยทยท\n", + "loading Roboflow workspace...\n", + "loading Roboflow project...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "Downloading Dataset Version Zip in find_fish_bbox-1 to yolov8:: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 2151/2151 [00:00<00:00, 47828.05it/s]" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "\n", + "Extracting Dataset Version Zip to find_fish_bbox-1 in yolov8:: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 33/33 [00:00<00:00, 2669.62it/s]\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "\n", + "Class names written to /content/datasets/find_fish_bbox-1/label_maps.txt\n", + "\n", + "\n", + "Contents of label_maps.txt:\n", + "\n", + "black_orange_fish\n", + "smaller_white_fish\n", + "striped_fish\n", + "white_fish\n", + "yellow_fish\n", + "\n", + "Class Counts:\n", + " {\n", + " \"3\": 36,\n", + " \"4\": 9,\n", + " \"0\": 3,\n", + " \"1\": 4,\n", + " \"2\": 2\n", + "}\n", + "\n", + "Underrepresented Class Factors:\n", + " {\n", + " \"4\": 4,\n", + " \"0\": 12,\n", + " \"1\": 9,\n", + " \"2\": 18\n", + "}\n", + "Files deleted where label does not exist:\n", + "/content/datasets/find_fish_bbox-1/train/upload/images/PXL_20231012_075201332_TS_mp4-0_jpg.rf.aecd4ec8d2bdec78f76bfa164b302a0f_class_4_2_masked_aug_2.jpg\n", + "/content/datasets/find_fish_bbox-1/train/upload/labels/PXL_20231012_075201332_TS_mp4-0_jpg.rf.aecd4ec8d2bdec78f76bfa164b302a0f_class_4_2_masked_aug_2.txt\n", + "/content/datasets/find_fish_bbox-1/train/upload/images/PXL_20231012_075201332_TS_mp4-2_jpg.rf.8807edbacd38658b1b10570f4b97fb3a_class_0_1_masked_aug_11.jpg\n", + "/content/datasets/find_fish_bbox-1/train/upload/labels/PXL_20231012_075201332_TS_mp4-2_jpg.rf.8807edbacd38658b1b10570f4b97fb3a_class_0_1_masked_aug_11.txt\n", + "\n", + "\n", + "Number of .jpg files to upload: 142\n", + "\n", + "\n", + "{'image': {'success': True, 'id': 'YHCULl1OhtpFa5fAoV4Y'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'uORNhlPQ9IC5Bxym6wSt'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'hOQSbUqgXlCoTIlRbgxp'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'PRj8WOEQJKnuYvOcGQEg'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'w34sqn3Ly25WAZSVeNUS'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '5hiwrIpGPs6RK6d64Ybm'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'sWo9sUNO0DhVlnh0EBzy'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'ra5uBDQEErSYiCz5y3pb'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'QofMyYsHoAiwrQcjtF6I'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '6VSNKuzXQfSMNzR8D886'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'D7waOHRJZ0M7r0HWgBMT'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'oSIIIqUg2poF9j2Iu2rh'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'QXPayItoEvgYovhVAqAN'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'yrz8tJzV3BuTPINEKZJm'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'ck7mVGlBg4xD8vBuoDwa'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'GJF3M9Zpa4NPoOj9Wm47'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '0btcXfhquABshUDoC5x7'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'fPEy3WhpMkyvmYYRxc1Z'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'TxHRI1CaUCLaFy9j6e8L'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'vuETwJA5bH5CdiYYw3tx'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'TJ8cgU4Ih1i8wu7D8w7w'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'eazMOiilO7UpqMbOzrGU'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'wqXFZstvloLM4DYnqcmz'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'pWIL3luni7i0SSxs3zTQ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'XCBq2LQ3EjSrJGkDQMee'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'Qcn3TDme910rzHv8XJDE'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'jPJXehXIdKebt5fUF2VD'}, 'annotation': {'success': True, 'warnings': True, 'badAnnotations': [{'type': 'warning', 'code': 'annotation:trimmed', 'key': 'PXL_20231012_075201332_TS_mp4-0_jpg.rf.aecd4ec8d2bdec78f76bfa164b302a0f_class_4_2_masked_aug_0.jpg', 'label': 'yellow_fish'}]}}\n", + "{'image': {'success': True, 'id': 'oXV13ubfiYxWFLWlccrN'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'qid6ZO6xD68S8RVhoV2G'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '85bfp4HzsvX3WyVcLYqI'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'EhwgxMCoFtjCALMH32ec'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'fpmyeo1c7TGEGDeaEGPJ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '2AD8HbFLTTRtevUPzsRC'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'mcmek78x1bcS9gF0oSgE'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'kU04pwin3pqLUbVcMdpK'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'JibinYImYqTesaz9tv56'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'kDCLTAPEuFo3HkKaMbE3'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'lz691BveA6RwDQ4I1YUL'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '9xGbrYxoVep3Cs06xUKb'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'fLmBNHyhiHrA9zKC7Yct'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'yEX3TtdR1ZOyugUG0z0c'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 's5yMMiO2QNeWrZQLlz75'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'cQDUp47vNasdbhMQwz5n'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'aXBjzECXD4eon3hgUstZ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'gwoysg6oXRJ0DlwEKmuo'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'ryfdklxh6e1319PTnLoJ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'Jmg4rjsNhuE9sDmOwJei'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'Rsbl5ys5LZEUXNvS66Lv'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'pIJ1JQLuyL46kKSwTUsj'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'KllusMs7GdAEKrCP17nh'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'OAdJUqysnlwboJmxMccU'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'zvLgZgLNA6Am9jMiMd4j'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'IyEcQGzpssElV22JjDeA'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'RvBqEPYyzh7BWbHrIlLR'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '73Ls6DBDuhhMqTwC2Deu'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'tgOrZGwujCp2m5HTVde8'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'Sr5jRM2b0KHmJiVXS2Y9'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'R5fK4XbdHFkM2kTswN4J'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'WgZnybBdDJxJnDrx20mQ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'xGEj7WgvEDpkx53MWjjM'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'AgBjaKwxi50HAbUDCtYZ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'oxFR7igf20JWvxICd6oo'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '9BTLlhZ92acSheGN76De'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'AJBHyFzGnY6h4TEpehRA'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '1fn6cTknrepdEeywuVaJ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'sHcaSTAf1wMM8h1xMiMX'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'd1OdWmS186g7ilFiovH8'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'R9o27Eu8Uwta2dBU5g9N'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'inrIQKYGy3biCzBgyAC3'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'gmLUVbP4aPRnHw0Vjiw0'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'Z7J9n0A9lbJRgvzyK9cI'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'I14ntwLVYSE9DMbsQQs3'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'xDqm6noy3IVMBu81ZRVP'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '5fgTxg6b9XAXdJROkEzx'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'd9MKTn9b2Mi5mExYlr0W'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'OoHUXgp6Xdne5SdQUk09'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'tBmc2Bl8jjB8iXbxG1We'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'VZ1BX7QrGPMROYqcIbzq'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'R4E64VCDydREHnCUV05z'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'bnf0RF1kk025yhkjzhmG'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'rudnutlarIyfleFd14Rd'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'grJEIpp77lAIzfZWVKvv'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'S6R0TASjsW1hJZMbqjoy'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'Ti9TjX13VBMDLOYnxkXC'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'bSetysiRlVa8EmotmdEE'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'QEVe1PWCTivyrh5sJjQr'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'sva5LRFMiKvSy0gRrfWy'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'CVuQdReUucDe0T2PNZcb'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'EQSYeoTXC6pUE7KBfQLc'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '2zNAjEo3mEQ0Y9b9MRaR'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'QBchoDO8XLdoSVk2Abaa'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'ti9J9hfqqECgUSqXxIg0'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'qsVWYa8Pz33iLsr9PFy8'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '8epxxOaLtauNB1inotUJ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'GcWnK21Lvltuq53kvxBc'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'MQBjFGOrX2LWeUFQsGhj'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'En4QLD1Zh4qPkIch6mL0'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'dNTNoakOrIdpMH4ix6Qj'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'Snf0tS0tLfdz38gJXTwn'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'yIQ2IGtEiZiXqXcpsu5J'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'd2KIG8dAs85HJR4u9KDR'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'U8rO8vqaKQBeD4pK9Qis'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'VNuQVBdYyYgXfwNI3vdX'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '0q9OcdOjWEJ95TL2RALG'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'w0mDw3QPa21hOumuWWOv'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'aIC0fjFDXKRxjPikdkXG'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'XDQusEai79Pywu22xZfS'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'MPb5ogem8pGXaUvb6AGK'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'x6nLAOJOpmLIfUvdOJu9'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'iAZgNdOEih8S6fplpiWt'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '5Yft56ySTXjFRPyCHgbT'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'XojqxDefWvaQHZpVZR5V'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'j6iKKubvBdcfDYKBkVsC'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'aQVg45iXMVC7aPTbGqHg'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '43J0gdtzgYxwhKZfOZNp'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'NXkXNwGl6xDjP4jxVgMc'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'KFoAD69Tg9xU0MYnylTt'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'CqhKKv8idnxSDSRdjWVy'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'BcxYEC38CinmnL4EC8zu'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'mOjUYMMRW9mFtr1bVXIi'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'j3swclMx27CwzzoAfUsc'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'nB8qyWljlJQLarSEEocg'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'BZbMmVfVUi1ObxKXbZmP'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'LG7qrMYFnUCi1mtKezNJ'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '9QBUAgg5DJuWk2DRJlR9'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'YFOq8ob1vTQ667H5wqod'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'divkC5ijcFJSvLelc9QY'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '2xzRC7Ri8SftBoNxWDpy'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'ZfHfEbtXjoD2i32EKKb5'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'DGongYl0xzBidWtZvY5T'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'oHOFtWWSJzvAcVxn7uJK'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'wxM9ShBNg1ONu2ATzyDz'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'XriIXvbRS9j4I4L4t98F'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'ZliyKbDasIhn5NOUotjA'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'tUYKRYQNyso8KGikBObu'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'sVjqin0tJMmtBM1hSten'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'wxgeq67YVpmEnt8mb3yU'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '6ddej6jkOP4lfW5gIn6o'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'zccS47Ws4h3f2qPrZ7HI'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': '0eBJG3oXyX8q7BrjyOp8'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'mpEyc1xFXbg2FLDG9F7w'}, 'annotation': {'success': True}}\n", + "{'image': {'success': True, 'id': 'R8BRMlNZ1CNpTnBcU8S6'}, 'annotation': {'success': True}}\n" + ] + } + ] + } + ] +} \ No newline at end of file