{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Spike Wheat Dataset\n\nIn this kernel I present my version of Spike Wheat dataset downladed from [here](https://sourceforge.net/projects/spike-dataset/) and first mentioned [here](https://www.kaggle.com/c/global-wheat-detection/discussion/164346). I couldn't find a proper licensing though. I am presenting it here for the community to see if it helps. Personaly, I have mixed results regarding using it. There are two versions of the dataset:\n* In the *original* version every image is squeezed into 1024x1024\n* In the second version I split every original image into a 2x2 grid, because the original version of the images were 1920 × 1080 and I resize in 1024x1024. This version is split into training and validation subsets.\n\nThe format of both datasets is yolov5 ready :). In this kernel I create a custom dataset and show some examples, suitable for other frameworks as well. There is still time to take advantage of these images provided that we are allowed to. Please do inform me if you see any improvements after using it. \n","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfrom torch.utils.data import Dataset,DataLoader\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport cv2\nfrom matplotlib import pyplot as plt\nimport torch\n","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"#\n# Super cool Dataset from https://www.kaggle.com/shonenkov/training-efficientdet\nclass DatasetRetriever(Dataset):\n\n    def __init__(self, marking, image_ids, transforms=None, test=False):\n        super().__init__()\n\n        self.image_ids = image_ids\n        self.marking = marking\n        self.transforms = transforms\n        self.test = test\n        self.alpha = 1.0\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        if self.test or random.random() > 0.55:\n            image, boxes = self.load_image_and_boxes(index)\n        else:\n            #if random.random() > 0.70:\n            image, boxes = self.load_cutmix_image_and_boxes(index)\n            #else:\n            #    image, boxes = self.load_mixup_v1(index)\n                \n\n        # there is only one class\n        labels = torch.ones((boxes.shape[0],), dtype=torch.int64)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['labels'] = labels\n        target['image_id'] = torch.tensor([index])\n\n        if self.transforms:\n            for i in range(10):\n                sample = self.transforms(**{\n                    'image': image,\n                    'bboxes': target['boxes'],\n                    'labels': labels\n                })\n                if len(sample['bboxes']) > 0:\n                    image = sample['image']\n                    target['boxes'] = torch.stack(tuple(map(torch.tensor, zip(*sample['bboxes'])))).permute(1, 0)\n                    target['boxes'][:,[0,1,2,3]] = target['boxes'][:,[1,0,3,2]]  #yxyx: be warning\n                    break\n\n        return image, target, image_id\n\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]\n    \n    \n    def clahe(self, bgr, gridsize=8):\n        lab = cv2.cvtColor(bgr, cv2.COLOR_BGR2LAB)\n        lab_planes = cv2.split(lab)\n        clahe = cv2.createCLAHE(clipLimit=4.0,tileGridSize=(gridsize,gridsize))\n        lab_planes[0] = clahe.apply(lab_planes[0])\n        lab = cv2.merge(lab_planes)\n        bgr_e = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)\n        return bgr_e\n\n    def load_image_and_boxes(self, index):\n        image_id = self.image_ids[index]\n        records = self.marking[self.marking['image_id'] == image_id]\n        base_path = records['base_path'].values[0]\n        \n        image = cv2.imread(f'{base_path}/{image_id}.jpg', cv2.IMREAD_COLOR)\n        ##\n        ##adde clahe one out of three!!\n        if np.random.rand() < 0.3 and not self.test:\n            image = self.clahe(image, np.random.randint(6, 11))\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n        boxes = records[['x', 'y', 'w', 'h']].values\n        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]\n        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n        return image, boxes\n    \n    \n    def load_mixup_v1(self, index):\n        lam = np.random.beta(self.alpha, self.alpha)\n\n        image, boxes = self.load_image_and_boxes(index)\n        r_image, r_boxes = self.load_image_and_boxes(random.randint(0, self.image_ids.shape[0] - 1))\n        mixup_image = lam*image+(1-lam)*r_image\n\n        mixup_boxes = []\n        for box in boxes.astype(int):\n            mixup_boxes.append(box)\n\n        for box in r_boxes.astype(int):\n            mixup_boxes.append(box)\n        mixup_boxes = np.array(mixup_boxes)  \n        return mixup_image, mixup_boxes\n\n    def load_cutmix_image_and_boxes(self, index, imsize=1024):\n        \"\"\" \n        This implementation of cutmix author:  https://www.kaggle.com/nvnnghia \n        Refactoring and adaptation: https://www.kaggle.com/shonenkov\n        \"\"\"\n        w, h = imsize, imsize\n        s = imsize // 2\n    \n        xc, yc = [int(random.uniform(imsize * 0.25, imsize * 0.75)) for _ in range(2)]  # center x, y\n        indexes = [index] + [random.randint(0, self.image_ids.shape[0] - 1) for _ in range(3)]\n\n        result_image = np.full((imsize, imsize, 3), 1, dtype=np.float32)\n        result_boxes = []\n\n        for i, index in enumerate(indexes):\n            image, boxes = self.load_image_and_boxes(index)\n            if i == 0:\n                x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc  # xmin, ymin, xmax, ymax (large image)\n                x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h  # xmin, ymin, xmax, ymax (small image)\n            elif i == 1:  # top right\n                x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc\n                x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h\n            elif i == 2:  # bottom left\n                x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)\n                x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, max(xc, w), min(y2a - y1a, h)\n            elif i == 3:  # bottom right\n                x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h)\n                x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h)\n            result_image[y1a:y2a, x1a:x2a] = image[y1b:y2b, x1b:x2b]\n            padw = x1a - x1b\n            padh = y1a - y1b\n\n            boxes[:, 0] += padw\n            boxes[:, 1] += padh\n            boxes[:, 2] += padw\n            boxes[:, 3] += padh\n\n            result_boxes.append(boxes)\n\n        result_boxes = np.concatenate(result_boxes, 0)\n        np.clip(result_boxes[:, 0:], 0, 2 * s, out=result_boxes[:, 0:])\n        result_boxes = result_boxes.astype(np.int32)\n        result_boxes = result_boxes[np.where((result_boxes[:,2]-result_boxes[:,0])*(result_boxes[:,3]-result_boxes[:,1]) > 0)]\n        return result_image, result_boxes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"SIZE = 512\ndef get_valid_transforms():\n    return A.Compose(\n        [\n            A.Resize(height=SIZE, width=SIZE, p=1.0),\n            ToTensorV2(p=1.0),\n        ], \n        p=1.0, \n        bbox_params=A.BboxParams(\n            format='pascal_voc',\n            min_area=0, \n            min_visibility=0,\n            label_fields=['labels']\n        )\n    )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 1. Original version","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#\n# wheat original version\n\noriginal_size = 1024\nskpike_valid_images = '../input/wheat-dataset-original/convertor/images/'\nskpike_valid_labels = '../input/wheat-dataset-original/convertor/labels/'\nwe_images = os.listdir(skpike_valid_images)\nwe_labels = os.listdir(skpike_valid_labels)\nwe_images = np.sort(we_images)\nwe_labels = np.sort(we_labels)\nspike_df_train_orig = None\nfor (lab, img) in zip(we_labels, we_images):\n    df = pd.read_csv(skpike_valid_labels + '/' + lab, sep=' ', header=None)\n    df.columns = ['class', 'x', 'y', 'w', 'h']\n    df['x'] = (1024 * df['x'])\n    df['y'] = np.ceil(1024 * df['y'])\n    df['w'] = np.floor(1024 * df['w'])\n    df['h'] = np.floor(1024 * df['h'])\n    df['x'] = np.ceil(df['x'] - df['w']/2 - 1)\n    df['y'] = np.ceil(df['y'] - df['h']/2 - 1)\n    \n    df['x'] = df['x'].clip(0.1, 1023)\n    df['y'] = df['y'].clip(0.1, 1023)\n    keep_idx = df['w'] > 1\n    df = df[keep_idx]\n    keep_idx = df['h'] > 1\n    df = df[keep_idx]\n    \n    \n    \n    df['image_id'] = img.split('.')[0]\n    df['base_path'] = '../input/wheat-dataset-original/convertor/images/'\n    df['width'] = 1024\n    df['height'] = 1024\n    df['source'] = 'spike'\n    df = df.drop(['class'], axis=1)\n    df = df[['image_id', 'width', 'height', 'source', 'x', 'y', 'w', 'h', 'base_path']]\n    \n    \n    #print ( lab, img)\n    if spike_df_train_orig is None:\n        spike_df_train_orig = df.copy()\n    else:\n        spike_df_train_orig = pd.concat((spike_df_train_orig, df))\nspike_df_train_orig.head()    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndataset_spike = DatasetRetriever(\n    image_ids=spike_df_train_orig['image_id'].unique(),\n    marking=spike_df_train_orig,\n    transforms=get_valid_transforms(),\n    test=True,\n)\nprint (f'There are {len(dataset_spike)} images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(5):\n    image, target, image_id = dataset_spike[5*i]\n    boxes = target['boxes'].cpu().numpy().astype(np.int32)\n\n    numpy_image = image.permute(1,2,0).cpu().numpy()\n\n    fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\n    for box in boxes:\n        cv2.rectangle(numpy_image, (box[1], box[0]), (box[3],  box[2]), (0, 1, 0), 2)\n\n    ax.set_axis_off()\n    ax.imshow(numpy_image);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 2. Split version","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"#\n# wheat spike split (2nd) version\n\noriginal_size = 1024\nskpike_valid_images = '../input/spike-dataset/images/train/'\nskpike_valid_labels = '../input/spike-dataset/labels/train/'\nwe_images = os.listdir(skpike_valid_images)\nwe_labels = os.listdir(skpike_valid_labels)\nwe_images = np.sort(we_images)\nwe_labels = np.sort(we_labels)\nspike_df_train = None\nfor (lab, img) in zip(we_labels, we_images):\n    df = pd.read_csv(skpike_valid_labels + '/' + lab, sep=' ', header=None)\n    df.columns = ['class', 'x', 'y', 'w', 'h']\n    df['x'] = (1024 * df['x'])\n    df['y'] = np.ceil(1024 * df['y'])\n    df['w'] = np.floor(1024 * df['w'])\n    df['h'] = np.floor(1024 * df['h'])\n    df['x'] = np.ceil(df['x'] - df['w']/2 - 1)\n    df['y'] = np.ceil(df['y'] - df['h']/2 - 1)\n    \n    df['x'] = df['x'].clip(0.1, 1023)\n    df['y'] = df['y'].clip(0.1, 1023)\n    keep_idx = df['w'] > 1\n    df = df[keep_idx]\n    keep_idx = df['h'] > 1\n    df = df[keep_idx]\n    \n    \n    \n    df['image_id'] = img.split('.')[0]\n    df['base_path'] = '../input/spike-dataset/images/train/'\n    df['width'] = 1024\n    df['height'] = 1024\n    df['source'] = 'spike'\n    df = df.drop(['class'], axis=1)\n    df = df[['image_id', 'width', 'height', 'source', 'x', 'y', 'w', 'h', 'base_path']]\n    \n    \n    #print ( lab, img)\n    if spike_df_train is None:\n        spike_df_train = df.copy()\n    else:\n        spike_df_train = pd.concat((spike_df_train, df))\nspike_df_train.head()    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndataset_spike = DatasetRetriever(\n    image_ids=spike_df_train['image_id'].unique(),\n    marking=spike_df_train,\n    transforms=get_valid_transforms(),\n    test=True,\n)\nprint (f'There are {len(dataset_spike)} images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(5):\n    image, target, image_id = dataset_spike[5*i]\n    boxes = target['boxes'].cpu().numpy().astype(np.int32)\n\n    numpy_image = image.permute(1,2,0).cpu().numpy()\n\n    fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\n    for box in boxes:\n        cv2.rectangle(numpy_image, (box[1], box[0]), (box[3],  box[2]), (0, 1, 0), 2)\n\n    ax.set_axis_off()\n    ax.imshow(numpy_image);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}