{"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":"# 1.导入库","metadata":{}},{"cell_type":"code","source":"import glob\nimport os\nimport cv2\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nplt.rcParams['figure.figsize'] = 30, 30\nnp.set_printoptions(precision=3, suppress=True)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:03.466597Z","iopub.execute_input":"2021-12-09T15:48:03.466868Z","iopub.status.idle":"2021-12-09T15:48:03.683224Z","shell.execute_reply.started":"2021-12-09T15:48:03.466840Z","shell.execute_reply":"2021-12-09T15:48:03.682371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2.加载数据集","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv('../input/tensorflow-great-barrier-reef/train.csv')\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:03.685264Z","iopub.execute_input":"2021-12-09T15:48:03.685671Z","iopub.status.idle":"2021-12-09T15:48:03.767416Z","shell.execute_reply.started":"2021-12-09T15:48:03.685627Z","shell.execute_reply":"2021-12-09T15:48:03.766572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3.数据可视化","metadata":{}},{"cell_type":"code","source":"from ast import literal_eval\n\n\ndef load_image(video_id, video_frame, image_dir):\n    img_path = f'{image_dir}/video_{video_id}/{video_frame}.jpg'\n    assert os.path.exists(img_path), f'{img_path} does not exist.'\n    img = cv2.imread(img_path)\n    return img\n\n\ndef decode_annotations(annotaitons_str):\n    \"\"\"decode annotations in string to list of dict\"\"\"\n    return literal_eval(annotaitons_str)\n\ndef load_image_with_annotations(video_id, video_frame, image_dir, annotaitons_str):\n    img = load_image(video_id, video_frame, image_dir)\n    annotations = decode_annotations(annotaitons_str)\n    if len(annotations) > 0:\n        for ann in annotations:\n            cv2.rectangle(img, (ann['x'], ann['y']),\n                (ann['x'] + ann['width'], ann['y'] + ann['height']),\n                (255, 0, 0), thickness=2,)\n    return img\n\ndef draw_predictions(img, pred_bboxes):\n    img = img.copy()\n    if len(pred_bboxes) > 0:\n        for bbox in pred_bboxes:\n            conf = bbox[0]\n            x, y, w, h = bbox[1:].round().astype(int)\n            cv2.rectangle(img, (x, y),\n                (x+w, y+h),\n                (0, 255, 255), thickness=2,)\n            cv2.putText(\n                img,\n                f\"{conf:.2}\",\n                (x, max(0, y-5)),\n                cv2.FONT_HERSHEY_SIMPLEX,\n                0.5,\n                (0, 0, 255),\n                thickness=1,\n            )\n    return img\n\n# test\n# index = 0\nindex = 19668\n# index = 16\nrow = df.iloc[index]\nvideo_id = row.video_id\nvideo_frame = row.video_frame\nannotations_str = row.annotations\nimage_dir = '../input/tensorflow-great-barrier-reef/train_images'\nimg = load_image_with_annotations(video_id, video_frame, image_dir, annotations_str)\nplt.imshow(img[:, :, ::-1])","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:03.768780Z","iopub.execute_input":"2021-12-09T15:48:03.769004Z","iopub.status.idle":"2021-12-09T15:48:05.765222Z","shell.execute_reply.started":"2021-12-09T15:48:03.768978Z","shell.execute_reply":"2021-12-09T15:48:05.763787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3.生成真实情况和虚拟预测","metadata":{}},{"cell_type":"code","source":"def generate_gt_and_pred(annotations_str):\n    annotations = decode_annotations(annotations_str)\n\n    gt_bboxes = []\n    pred_bboxes = []\n\n    for ann in annotations:\n        gt_bboxes.append(np.array([ann['x'], ann['y'], ann['width'], ann['height']]))\n\n        # pseudo pred bbox\n        conf = np.random.uniform()\n        noise = (np.random.randn(4)*5).round()\n        pred_bbox = np.array([conf, ann['x'], ann['y'], ann['width'], ann['height']])\n        pred_bbox[1:] = pred_bbox[1:] + noise\n        pred_bboxes.append(pred_bbox)\n\n    gt_bboxes = np.array(gt_bboxes)\n    pred_bboxes = np.array(pred_bboxes)\n    return gt_bboxes, pred_bboxes\n\nannotations_str = df.iloc[index]['annotations']\ngt_bboxes, pred_bboxes = generate_gt_and_pred(annotations_str)\n\nif len(pred_bboxes) > 0:\n    pred_bboxes = pred_bboxes[pred_bboxes[:,0].argsort()[::-1]] # sort by conf\n    pred_img = draw_predictions(img, pred_bboxes)\n    plt.imshow(pred_img[:, :, ::-1])","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:05.766740Z","iopub.execute_input":"2021-12-09T15:48:05.767783Z","iopub.status.idle":"2021-12-09T15:48:07.713770Z","shell.execute_reply.started":"2021-12-09T15:48:05.767733Z","shell.execute_reply":"2021-12-09T15:48:07.712996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4.实现图像的度量\n\n* 其中f2_score是fbeta_score中beta=2的情况。","metadata":{}},{"cell_type":"code","source":"def calc_iou(bboxes1, bboxes2, bbox_mode='xywh'):\n    assert len(bboxes1.shape) == 2 and bboxes1.shape[1] == 4\n    assert len(bboxes2.shape) == 2 and bboxes2.shape[1] == 4\n    \n    bboxes1 = bboxes1.copy()\n    bboxes2 = bboxes2.copy()\n    \n    if bbox_mode == 'xywh':\n        bboxes1[:, 2:] += bboxes1[:, :2]\n        bboxes2[:, 2:] += bboxes2[:, :2]\n\n    x11, y11, x12, y12 = np.split(bboxes1, 4, axis=1)\n    x21, y21, x22, y22 = np.split(bboxes2, 4, axis=1)\n    xA = np.maximum(x11, np.transpose(x21))\n    yA = np.maximum(y11, np.transpose(y21))\n    xB = np.minimum(x12, np.transpose(x22))\n    yB = np.minimum(y12, np.transpose(y22))\n    interArea = np.maximum((xB - xA + 1), 0) * np.maximum((yB - yA + 1), 0)\n    boxAArea = (x12 - x11 + 1) * (y12 - y11 + 1)\n    boxBArea = (x22 - x21 + 1) * (y22 - y21 + 1)\n    iou = interArea / (boxAArea + np.transpose(boxBArea) - interArea)\n    return iou\n\ndef f_beta(tp, fp, fn, beta=2):\n    return (1+beta**2)*tp / ((1+beta**2)*tp + beta**2*fn+fp)\n\ndef imagewise_f2_score_at_iou_th(gt_bboxes, pred_bboxes, iou_th, verbose=False):\n    gt_bboxes = gt_bboxes.copy()\n    pred_bboxes = pred_bboxes.copy()\n    \n    tp = 0\n    fp = 0\n    for pred_bbox in pred_bboxes:\n        ious = calc_iou(gt_bboxes, pred_bbox[None, 1:])\n        max_iou = ious.max()\n        if max_iou > iou_th:\n            tp += 1\n            gt_bboxes = np.delete(gt_bboxes, ious.argmax(), axis=0)\n        else:\n            fp += 1\n        if len(gt_bboxes) == 0:\n            fp += len(pred_bboxes)\n            break\n\n    fn = len(gt_bboxes)\n    score = f_beta(tp, fp, fn, beta=2)\n    if verbose:\n        print(f'iou_th:{iou_th.round(2):<4} tp:{tp:<2}, fp:{fp:<2}, fn:{fn:<2} f2:{score:.3}')\n    return score\n\ndef imagewise_f2_score(gt_bboxes, pred_bboxes, verbose=False):\n    \"\"\"\n    gt_bboxes: (N, 4) np.array in xywh format\n    pred_bboxes: (N, 5) np.array in conf+xywh format\n    \"\"\"\n    # v2: add corner case hundling.\n    if len(gt_bboxes) == 0 and len(pred_bboxes) == 0:\n        return 1.0\n    elif len(gt_bboxes) == 0 or len(pred_bboxes) == 0:\n        return 0.0\n    \n    pred_bboxes = pred_bboxes[pred_bboxes[:,0].argsort()[::-1]] # sort by conf\n    \n    scores = []\n    for iou_th in np.arange(0.3, 0.85, 0.05):\n        scores.append(imagewise_f2_score_at_iou_th(gt_bboxes, pred_bboxes, iou_th, verbose))\n    return np.mean(scores)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:07.715556Z","iopub.execute_input":"2021-12-09T15:48:07.716552Z","iopub.status.idle":"2021-12-09T15:48:07.735832Z","shell.execute_reply.started":"2021-12-09T15:48:07.716496Z","shell.execute_reply":"2021-12-09T15:48:07.735003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"imagewise_f2_score(gt_bboxes, pred_bboxes, verbose=True)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:07.737140Z","iopub.execute_input":"2021-12-09T15:48:07.737417Z","iopub.status.idle":"2021-12-09T15:48:07.792881Z","shell.execute_reply.started":"2021-12-09T15:48:07.737386Z","shell.execute_reply":"2021-12-09T15:48:07.792095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5.全局 f2 度量实现","metadata":{}},{"cell_type":"code","source":"def calc_iou(bboxes1, bboxes2, bbox_mode='xywh'):\n    assert len(bboxes1.shape) == 2 and bboxes1.shape[1] == 4\n    assert len(bboxes2.shape) == 2 and bboxes2.shape[1] == 4\n    \n    bboxes1 = bboxes1.copy()\n    bboxes2 = bboxes2.copy()\n    \n    if bbox_mode == 'xywh':\n        bboxes1[:, 2:] += bboxes1[:, :2]\n        bboxes2[:, 2:] += bboxes2[:, :2]\n\n    x11, y11, x12, y12 = np.split(bboxes1, 4, axis=1)\n    x21, y21, x22, y22 = np.split(bboxes2, 4, axis=1)\n    xA = np.maximum(x11, np.transpose(x21))\n    yA = np.maximum(y11, np.transpose(y21))\n    xB = np.minimum(x12, np.transpose(x22))\n    yB = np.minimum(y12, np.transpose(y22))\n    interArea = np.maximum((xB - xA + 1), 0) * np.maximum((yB - yA + 1), 0)\n    boxAArea = (x12 - x11 + 1) * (y12 - y11 + 1)\n    boxBArea = (x22 - x21 + 1) * (y22 - y21 + 1)\n    iou = interArea / (boxAArea + np.transpose(boxBArea) - interArea)\n    return iou\n\ndef f_beta(tp, fp, fn, beta=2):\n    return (1+beta**2)*tp / ((1+beta**2)*tp + beta**2*fn+fp)\n\ndef calc_is_correct_at_iou_th(gt_bboxes, pred_bboxes, iou_th, verbose=False):\n    gt_bboxes = gt_bboxes.copy()\n    pred_bboxes = pred_bboxes.copy()\n    \n    tp = 0\n    fp = 0\n    for pred_bbox in pred_bboxes:\n        ious = calc_iou(gt_bboxes, pred_bbox[None, 1:])\n        max_iou = ious.max()\n        if max_iou > iou_th:\n            tp += 1\n            gt_bboxes = np.delete(gt_bboxes, ious.argmax(), axis=0)\n        else:\n            fp += 1\n        if len(gt_bboxes) == 0:\n            fp += len(pred_bboxes)\n            break\n\n    fn = len(gt_bboxes)\n    return tp, fp, fn\n\ndef calc_is_correct(gt_bboxes, pred_bboxes):\n    \"\"\"\n    gt_bboxes: (N, 4) np.array in xywh format\n    pred_bboxes: (N, 5) np.array in conf+xywh format\n    \"\"\"\n    if len(gt_bboxes) == 0 and len(pred_bboxes) == 0:\n        tps, fps, fns = 0, 0, 0\n        return tps, fps, fns\n    \n    elif len(gt_bboxes) == 0:\n        tps, fps, fns = 0, len(pred_bboxes), 0\n        return tps, fps, fns\n    \n    elif len(pred_bboxes) == 0:\n        tps, fps, fns = 0, 0, len(gt_bboxes)\n        return tps, fps, fns\n    \n    pred_bboxes = pred_bboxes[pred_bboxes[:,0].argsort()[::-1]] # sort by conf\n    \n    tps, fps, fns = 0, 0, 0\n    for iou_th in np.arange(0.3, 0.85, 0.05):\n        tp, fp, fn = calc_is_correct_at_iou_th(gt_bboxes, pred_bboxes, iou_th)\n        tps += tp\n        fps += fp\n        fns += fn\n    return tps, fps, fns\n\ndef calc_f2_score(gt_bboxes_list, pred_bboxes_list, verbose=False):\n    \"\"\"\n    gt_bboxes_list: list of (N, 4) np.array in xywh format\n    pred_bboxes_list: list of (N, 5) np.array in conf+xywh format\n    \"\"\"\n    tps, fps, fns = 0, 0, 0\n    for gt_bboxes, pred_bboxes in zip(gt_bboxes_list, pred_bboxes_list):\n        tp, fp, fn = calc_is_correct(gt_bboxes, pred_bboxes)\n        tps += tp\n        fps += fp\n        fns += fn\n        if verbose:\n            num_gt = len(gt_bboxes)\n            num_pred = len(pred_bboxes)\n            print(f'num_gt:{num_gt:<3} num_pred:{num_pred:<3} tp:{tp:<3} fp:{fp:<3} fn:{fn:<3}')\n    return f_beta(tps, fps, fns, beta=2)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:07.794041Z","iopub.execute_input":"2021-12-09T15:48:07.794337Z","iopub.status.idle":"2021-12-09T15:48:07.811658Z","shell.execute_reply.started":"2021-12-09T15:48:07.794310Z","shell.execute_reply":"2021-12-09T15:48:07.810971Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6.生成 gt_bboxes 列表和虚拟 pred_bboxes 列表","metadata":{}},{"cell_type":"code","source":"gt_df = df.iloc[15:20]\ndisplay(gt_df)\n\ngt_bboxes_list = []\npred_bboxes_list = []\nfor ann_str in gt_df['annotations']:\n    gt_bboxes, pred_bboxes = generate_gt_and_pred(ann_str)\n    gt_bboxes_list.append(gt_bboxes)\n    pred_bboxes_list.append(pred_bboxes)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:07.812975Z","iopub.execute_input":"2021-12-09T15:48:07.813213Z","iopub.status.idle":"2021-12-09T15:48:07.834983Z","shell.execute_reply.started":"2021-12-09T15:48:07.813186Z","shell.execute_reply":"2021-12-09T15:48:07.833980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"calc_f2_score(gt_bboxes_list, pred_bboxes_list, verbose=True)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T15:48:07.836158Z","iopub.execute_input":"2021-12-09T15:48:07.836882Z","iopub.status.idle":"2021-12-09T15:48:07.849792Z","shell.execute_reply.started":"2021-12-09T15:48:07.836851Z","shell.execute_reply":"2021-12-09T15:48:07.848963Z"},"trusted":true},"execution_count":null,"outputs":[]}]}