{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport 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\n\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def iou(box, clusters):\n    \"\"\"\n    计算一个ground truth边界盒和k个先验框(Anchor)的交并比(IOU)值。\n    参数box: 元组或者数据，代表ground truth的长宽。\n    参数clusters: 形如(k,2)的numpy数组，其中k是聚类Anchor框的个数\n    返回：ground truth和每个Anchor框的交并比。\n    \"\"\"\n    x = np.minimum(clusters[:, 0], box[0])\n    y = np.minimum(clusters[:, 1], box[1])\n    if np.count_nonzero(x == 0) > 0 or np.count_nonzero(y == 0) > 0:\n        raise ValueError(\"Box has no area\")\n    intersection = x * y\n    box_area = box[0] * box[1]\n    cluster_area = clusters[:, 0] * clusters[:, 1]\n    iou_ = intersection / (box_area + cluster_area - intersection)\n    return iou_\n\n\ndef avg_iou(boxes, clusters):\n    \"\"\"\n    计算一个ground truth和k个Anchor的交并比的均值。\n    \"\"\"\n    return np.mean([np.max(iou(boxes[i], clusters)) for i in range(boxes.shape[0])])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"def kmeans(boxes, k=9, dist=np.median):\n    \"\"\"\n    利用IOU值进行K-means聚类\n    参数boxes: 形状为(r, 2)的ground truth框，其中r是ground truth的个数\n    参数k: Anchor的个数\n    参数dist: 距离函数\n    返回值：形状为(k, 2)的k个Anchor框\n    \"\"\"\n    # 即是上面提到的r\n    rows = boxes.shape[0]\n    # 距离数组，计算每个ground truth和k个Anchor的距离\n    distances = np.empty((rows, k))\n    # 上一次每个ground truth\"距离\"最近的Anchor索引\n    last_clusters = np.zeros((rows,))\n    # 设置随机数种子\n    np.random.seed()\n\n    # 初始化聚类中心，k个簇，从r个ground truth随机选k个\n    clusters = boxes[np.random.choice(rows, k, replace=False)]\n    # 开始聚类\n    while True:\n        # 计算每个ground truth和k个Anchor的距离，用1-IOU(box,anchor)来计算\n        for row in range(rows):\n            distances[row] = 1 - iou(boxes[row], clusters)\n        # 对每个ground truth，选取距离最小的那个Anchor，并存下索引\n        nearest_clusters = np.argmin(distances, axis=1)\n        # 如果当前每个ground truth\"距离\"最近的Anchor索引和上一次一样，聚类结束\n        if (last_clusters == nearest_clusters).all():\n            break\n        # 更新簇中心为簇里面所有的ground truth框的均值\n        for cluster in range(k):\n            clusters[cluster] = dist(boxes[nearest_clusters == cluster], axis=0)\n        # 更新每个ground truth\"距离\"最近的Anchor索引\n        last_clusters = nearest_clusters\n\n    return clusters","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def cvt_csv(whd_df):\n    # change dtype\n    whd_df[['bbox_xmin', 'bbox_ymin', 'bbox_width', 'bbox_height']] = whd_df['bbox'].str.split(',', expand=True)\n    whd_df['bbox_xmin'] = whd_df['bbox_xmin'].str.replace('[', '').astype(float)\n    whd_df['bbox_ymin'] = whd_df['bbox_ymin'].str.replace(' ', '').astype(float)\n    whd_df['bbox_width'] = whd_df['bbox_width'].str.replace(' ', '').astype(float)\n    whd_df['bbox_height'] = whd_df['bbox_height'].str.replace(']', '').astype(float)\n\n    # add xmax, ymax, and area columns for bounding box\n    whd_df['bbox_xmax'] = whd_df['bbox_xmin'] + whd_df['bbox_width']\n    whd_df['bbox_ymax'] = whd_df['bbox_ymin'] + whd_df['bbox_height']\n    whd_df['bbox_area'] = whd_df['bbox_height'] * whd_df['bbox_width']\n    whd_df['hw_ratio'] = whd_df['bbox_height'] / whd_df['bbox_width']\n\n    return whd_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv = '/kaggle/input/global-wheat-detection/train.csv'\ndf = pd.read_csv(train_csv)\ndf = cvt_csv(df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"h = df['bbox_height']\nw = df['bbox_width']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"boxes = np.array([w, h]).T\nboxes.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%time\ncluster_w_h = kmeans(boxes)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"w, h = np.split(cluster_w_h, 2, axis=1)\nratio = w / h\nratio = ratio.flatten()\nratio.sort()\nratio","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}