{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"##  Notebooks:\n* Train: [Great-Barrier-Reef: YOLOv5 [train] ](https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-train)\n* Infer: [Great-Barrier-Reef: YOLOv5 [infer] ](https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-infer)","metadata":{}},{"cell_type":"markdown","source":"#  下载包","metadata":{}},{"cell_type":"code","source":"#下载相关的包\n# !pip install -q imagesize\n# !pip install -qU wandb\n# !add-apt-repository ppa:ubuntu-toolchain-r/test -y\n# !apt-get update\n# !apt-get upgrade libstdc++6 -y","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#  导入工具包","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tqdm.notebook import tqdm\ntqdm.pandas()\nimport pandas as pd\nimport os\nimport cv2\nimport matplotlib.pyplot as plt\nimport glob\nimport shutil\nimport sys\nsys.path.append('../input/tensorflow-great-barrier-reef')\nimport torch\nfrom PIL import Image\nimport ast","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:49:16.1809Z","iopub.execute_input":"2021-12-06T09:49:16.181445Z","iopub.status.idle":"2021-12-06T09:49:17.643619Z","shell.execute_reply.started":"2021-12-06T09:49:16.181343Z","shell.execute_reply":"2021-12-06T09:49:17.64261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ROOT_DIR  = '/kaggle/input/tensorflow-great-barrier-reef/'\nCKPT_PATH = '/kaggle/input/greatbarrierreef-yolov5-train-ds/yolov5/runs/train/exp/weights/best.pt'\nIMG_SIZE  = 1280\nCONF      = 0.15\nIOU       = 0.50\nAUGMENT   = False","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:49:21.860294Z","iopub.execute_input":"2021-12-06T09:49:21.860905Z","iopub.status.idle":"2021-12-06T09:49:21.865218Z","shell.execute_reply.started":"2021-12-06T09:49:21.860855Z","shell.execute_reply":"2021-12-06T09:49:21.864621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#拿到路径\ndef get_path(row):\n    row['image_path'] = f'{ROOT_DIR}/train_images/video_{row.video_id}/{row.video_frame}.jpg'\n    return row","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:49:30.739105Z","iopub.execute_input":"2021-12-06T09:49:30.739987Z","iopub.status.idle":"2021-12-06T09:49:30.744852Z","shell.execute_reply.started":"2021-12-06T09:49:30.739928Z","shell.execute_reply":"2021-12-06T09:49:30.744192Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#  导入训练集\n","metadata":{}},{"cell_type":"code","source":"# 导入训练集\ndf = pd.read_csv(f'{ROOT_DIR}/train.csv')\ndf = df.progress_apply(get_path, axis=1)\ndf['annotations'] = df['annotations'].progress_apply(lambda x: ast.literal_eval(x))\ndisplay(df.head(5))","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:49:35.113166Z","iopub.execute_input":"2021-12-06T09:49:35.113488Z","iopub.status.idle":"2021-12-06T09:49:53.184641Z","shell.execute_reply.started":"2021-12-06T09:49:35.113457Z","shell.execute_reply":"2021-12-06T09:49:53.183676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 统计BBoxes数量\n近 80% 的图像没有任何 bbox。","metadata":{}},{"cell_type":"code","source":"df['num_bbox'] = df['annotations'].progress_apply(lambda x: len(x))\ndata = (df.num_bbox>0).value_counts()/len(df)*100\nprint(f\"No BBox: {data[0]:0.2f}% | With BBox: {data[1]:0.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:49:57.301445Z","iopub.execute_input":"2021-12-06T09:49:57.301752Z","iopub.status.idle":"2021-12-06T09:49:57.41071Z","shell.execute_reply.started":"2021-12-06T09:49:57.30172Z","shell.execute_reply":"2021-12-06T09:49:57.4097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 编写可用函数","metadata":{}},{"cell_type":"code","source":"def voc2yolo(bboxes, image_height=720, image_width=1280):\n    bboxes = bboxes.copy().astype(float) # 否则所有值都将为 0，因为 voc_pascal dtype 是 np.int\n    \n    bboxes[..., [0, 2]] = bboxes[..., [0, 2]]/ image_width\n    bboxes[..., [1, 3]] = bboxes[..., [1, 3]]/ image_height\n    \n    w = bboxes[..., 2] - bboxes[..., 0]\n    h = bboxes[..., 3] - bboxes[..., 1]\n    \n    bboxes[..., 0] = bboxes[..., 0] + w/2\n    bboxes[..., 1] = bboxes[..., 1] + h/2\n    bboxes[..., 2] = w\n    bboxes[..., 3] = h\n    return bboxes\n\ndef yolo2voc(bboxes, image_height=720, image_width=1280):\n    bboxes = bboxes.copy().astype(float) # 否则所有值都将为 0，因为 voc_pascal dtype 是 np.int\n    bboxes[..., [0, 2]] = bboxes[..., [0, 2]]* image_width\n    bboxes[..., [1, 3]] = bboxes[..., [1, 3]]* image_height\n    bboxes[..., [0, 1]] = bboxes[..., [0, 1]] - bboxes[..., [2, 3]]/2\n    bboxes[..., [2, 3]] = bboxes[..., [0, 1]] + bboxes[..., [2, 3]]\n    return bboxes\n\ndef coco2yolo(bboxes, image_height=720, image_width=1280):\n    bboxes = bboxes.copy().astype(float) # 否则所有值都将为 0，因为 voc_pascal dtype 是 np.int\n    \n    # 标准化\n    bboxes[..., [0, 2]]= bboxes[..., [0, 2]]/ image_width\n    bboxes[..., [1, 3]]= bboxes[..., [1, 3]]/ image_height\n    \n    # 转换 (xmin, ymin) => (xmid, ymid)\n    bboxes[..., [0, 1]] = bboxes[..., [0, 1]] + bboxes[..., [2, 3]]/2\n    return bboxes\n\ndef yolo2coco(bboxes, image_height=720, image_width=1280):\n    bboxes = bboxes.copy().astype(float) # 否则所有值都将为 0，因为 voc_pascal dtype 是 np.int\n    \n    # 非规范化\n    bboxes[..., [0, 2]]= bboxes[..., [0, 2]]* image_width\n    bboxes[..., [1, 3]]= bboxes[..., [1, 3]]* image_height\n    # 转换 (xmid, ymid) => (xmin, ymin) \n    bboxes[..., [0, 1]] = bboxes[..., [0, 1]] - bboxes[..., [2, 3]]/2\n    return bboxes\n\ndef voc2coco(bboxes, image_height=720, image_width=1280):\n    bboxes  = voc2yolo(bboxes, image_height, image_width)\n    bboxes  = yolo2coco(bboxes, image_height, image_width)\n    return bboxes\n\ndef load_image(image_path):\n    return cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)\n\ndef plot_one_box(x, img, color=None, label=None, line_thickness=None):\n    # 在图像 img 上绘制一个边界框\n    tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1  # 线条/字体粗细\n    color = color or [random.randint(0, 255) for _ in range(3)]\n    c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))\n    cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)\n    if label:\n        tf = max(tl - 1, 1)  # 字体粗细\n        t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]\n        c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3\n        cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA)  \n        cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)\n\ndef draw_bboxes(img, bboxes, classes, class_ids, colors = None, show_classes = None, bbox_format = 'yolo', class_name = False, line_thickness = 2):   \n    image = img.copy()\n    show_classes = classes if show_classes is None else show_classes\n    colors = (0, 255 ,0) if colors is None else colors\n    if bbox_format == 'yolo':  \n        for idx in range(len(bboxes)):         \n            bbox  = bboxes[idx]\n            cls   = classes[idx]\n            cls_id = class_ids[idx]\n            color = colors[cls_id] if type(colors) is list else colors     \n            if cls in show_classes:         \n                x1 = round(float(bbox[0])*image.shape[1])\n                y1 = round(float(bbox[1])*image.shape[0])\n                w  = round(float(bbox[2])*image.shape[1]/2) #w/2 \n                h  = round(float(bbox[3])*image.shape[0]/2)\n                voc_bbox = (x1-w, y1-h, x1+w, y1+h)\n                plot_one_box(voc_bbox, \n                             image,\n                             color = color,\n                             label = cls if class_name else str(get_label(cls)),\n                             line_thickness = line_thickness)     \n    elif bbox_format == 'coco':\n        for idx in range(len(bboxes)):     \n            bbox  = bboxes[idx]\n            cls   = classes[idx]\n            cls_id = class_ids[idx]\n            color = colors[cls_id] if type(colors) is list else colors \n            if cls in show_classes:            \n                x1 = int(round(bbox[0]))\n                y1 = int(round(bbox[1]))\n                w  = int(round(bbox[2]))\n                h  = int(round(bbox[3]))\n                voc_bbox = (x1, y1, x1+w, y1+h)\n                plot_one_box(voc_bbox, \n                             image,\n                             color = color,\n                             label = cls if class_name else str(cls_id),\n                             line_thickness = line_thickness)\n    elif bbox_format == 'voc_pascal':\n        for idx in range(len(bboxes)):  \n            bbox  = bboxes[idx]\n            cls   = classes[idx]\n            cls_id = class_ids[idx]\n            color = colors[cls_id] if type(colors) is list else colors\n            if cls in show_classes: \n                x1 = int(round(bbox[0]))\n                y1 = int(round(bbox[1]))\n                x2 = int(round(bbox[2]))\n                y2 = int(round(bbox[3]))\n                voc_bbox = (x1, y1, x2, y2)\n                plot_one_box(voc_bbox, \n                             image,\n                             color = color,\n                             label = cls if class_name else str(cls_id),\n                             line_thickness = line_thickness)\n    else:\n        raise ValueError('wrong bbox format')\n    return image\ndef get_bbox(annots):\n    bboxes = [list(annot.values()) for annot in annots]\n    return bboxes\ndef get_imgsize(row):\n    row['width'], row['height'] = imagesize.get(row['image_path'])\n    return row\nnp.random.seed(32)\ncolors = [(np.random.randint(255), np.random.randint(255), np.random.randint(255))\\\n          for idx in range(1)]","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:50:03.003427Z","iopub.execute_input":"2021-12-06T09:50:03.003732Z","iopub.status.idle":"2021-12-06T09:50:03.0477Z","shell.execute_reply.started":"2021-12-06T09:50:03.003701Z","shell.execute_reply":"2021-12-06T09:50:03.046474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir -p /root/.config/Ultralytics\n!cp /kaggle/input/yolov5-font/Arial.ttf /root/.config/Ultralytics/","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:56:45.342506Z","iopub.execute_input":"2021-12-06T09:56:45.343161Z","iopub.status.idle":"2021-12-06T09:56:46.921169Z","shell.execute_reply.started":"2021-12-06T09:56:45.343079Z","shell.execute_reply":"2021-12-06T09:56:46.919851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 建立模型","metadata":{}},{"cell_type":"code","source":"def load_model(ckpt_path, conf=0.25, iou=0.50):\n    model = torch.hub.load('/kaggle/input/yolov5-lib-ds',\n                           'custom',\n                           path=ckpt_path,\n                           source='local',\n                           force_reload=True)\n    \n    model.conf = conf  # NMS 置信度阈值\n    model.iou  = iou  #NMS IoU 阈值\n    model.classes = None   # （可选列表）按类别过滤，即 = [0, 15, 16] 用于人、猫和狗\n    model.multi_label = False  # 每盒 NMS 多个标签\n    model.max_det = 1000  # 每个图像的最大检测数\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:56:55.941847Z","iopub.execute_input":"2021-12-06T09:56:55.942208Z","iopub.status.idle":"2021-12-06T09:56:55.949375Z","shell.execute_reply.started":"2021-12-06T09:56:55.942164Z","shell.execute_reply":"2021-12-06T09:56:55.948223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 编写可用函数","metadata":{}},{"cell_type":"code","source":"def predict(model, img, size=768, augment=False):\n    height, width = img.shape[:2]\n    results = model(img, size=size, augment=augment)  # 自定义推理大小\n    preds   = results.pandas().xyxy[0]\n    bboxes  = preds[['xmin','ymin','xmax','ymax']].values\n    if len(bboxes):\n        bboxes  = voc2coco(bboxes,height,width).astype(int)\n        confs   = preds.confidence.values\n        return bboxes, confs\n    else:\n        return [],[]\n    \ndef format_prediction(bboxes, confs):\n    annot = ''\n    if len(bboxes)>0:\n        for idx in range(len(bboxes)):\n            xmin, ymin, w, h = bboxes[idx]\n            conf             = confs[idx]\n            annot += f'{conf} {xmin} {ymin} {w} {h}'\n            annot +=' '\n        annot = annot.strip(' ')\n    return annot\n\ndef show_img(img, bboxes, bbox_format='yolo'):\n    names  = ['starfish']*len(bboxes)\n    labels = [0]*len(bboxes)\n    img    = draw_bboxes(img = img,\n                           bboxes = bboxes, \n                           classes = names,\n                           class_ids = labels,\n                           class_name = True, \n                           colors = colors, \n                           bbox_format = bbox_format,\n                           line_thickness = 2)\n    return Image.fromarray(img).resize((800, 400))","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:57:04.481888Z","iopub.execute_input":"2021-12-06T09:57:04.482275Z","iopub.status.idle":"2021-12-06T09:57:04.495511Z","shell.execute_reply.started":"2021-12-06T09:57:04.482237Z","shell.execute_reply":"2021-12-06T09:57:04.494667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 在训练集上进行推理预测","metadata":{}},{"cell_type":"code","source":"model = load_model(CKPT_PATH, conf=CONF, iou=IOU)\nimage_paths = df[df.num_bbox>1].sample(100).image_path.tolist()\nfor idx, path in enumerate(image_paths):\n    img = cv2.imread(path)[...,::-1]\n    bboxes, confis = predict(model, img, size=IMG_SIZE, augment=AUGMENT)\n    display(show_img(img, bboxes, bbox_format='coco'))\n    if idx>5:\n        break","metadata":{"execution":{"iopub.status.busy":"2021-12-06T09:57:08.582389Z","iopub.execute_input":"2021-12-06T09:57:08.582698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 初始化环境","metadata":{}},{"cell_type":"code","source":"import greatbarrierreef\nenv = greatbarrierreef.make_env()# 初始化环境\niter_test = env.iter_test()      # 一个循环测试集和样本提交的迭代器","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 在测试集上进行推理预测","metadata":{}},{"cell_type":"code","source":"model = load_model(CKPT_PATH, conf=CONF, iou=IOU)\nfor idx, (img, pred_df) in enumerate(tqdm(iter_test)):\n    \n    bboxes, confs  = predict(model, img, size=IMG_SIZE, augment=True)\n    annot          = format_prediction(bboxes, confs)\n    pred_df['annotations'] = annot\n    \n    env.predict(pred_df)\n    if idx<3:\n        display(show_img(img, bboxes, bbox_format='coco'))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 检查提交结果","metadata":{}},{"cell_type":"code","source":"sub_df = pd.read_csv('submission.csv')\nsub_df.head()","metadata":{},"execution_count":null,"outputs":[]}]}