{"cells":[{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"markdown","source":"# My separate object algorithm\n- This notebook tells how to separate snowman-like object into circle or elliptic objects\n- Sorry my poor English"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"trusted":true},"cell_type":"code","source":"from collections import defaultdict\nimport os\nfrom glob import glob \nfrom imageio import imread\nfrom matplotlib import pyplot as plt\nimport cv2 \nimport pandas as pd \nimport numpy as np\nfrom scipy import ndimage\nfrom scipy.interpolate import splprep, splev\nimport skimage\nfrom skimage import measure \nfrom skimage.feature import peak_local_max\nfrom skimage.morphology import watershed","execution_count":1,"outputs":[]},{"metadata":{"_uuid":"87db517526c7a22cb09d3c00096d68196c20a8ec"},"cell_type":"markdown","source":"# Prepare Dataset "},{"metadata":{"trusted":true,"_uuid":"e7c5e6e2942236a0c2b09b1f293646283b9147c3"},"cell_type":"code","source":"stage1_train_path='../input/stage1_train/'\nfolders=os.listdir(stage1_train_path)\nfolders[:10]","execution_count":2,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0b5eb12c52b6ca84ae8a168ad3f1a58b376fb8ee"},"cell_type":"code","source":"stage1_csv_path = \"../input/stage1_train_labels.csv\"\ndf=pd.read_csv(stage1_csv_path)\ndf.head(5)","execution_count":3,"outputs":[]},{"metadata":{"_uuid":"2721694ee978cf0eccb137b21b79ddf2c7d7363c"},"cell_type":"markdown","source":"# Prepare CSV Decoder \n- This decoder is my handcrafted implementation. Please let me know if there is some bugs"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"e438180968521bf78ae61bf0c7a5b2a563866067"},"cell_type":"code","source":"class CSVDecoder(object):\n    def __init__(self, csv_path, train=True):\n        df = pd.read_csv(csv_path)\n\n        self.id_pixels = defaultdict(list)\n        for key in set(df['ImageId']):\n            subdf = df.query(\"ImageId=='{}'\".format(key))\n            value = [list(map(int, data.split(\" \")))\n                     for data in subdf[\"EncodedPixels\"]]\n            self.id_pixels[key] = value\n\n        basedir='../'\n\n        if train:\n            self.stage1_data_path = os.path.join(basedir,'input','stage1_train')\n        else:\n            self.stage1_data_path = os.path.join(basedir,'input','stage1_test')\n\n    def decode(self, imageid):\n        img_path = os.path.join(\n            self.stage1_data_path, imageid, 'images', imageid+'.png')\n        img = imread(img_path)\n        row, col = img.shape[:2]\n        label = np.zeros(row*col, dtype=int)\n        for encorded_pixels in self.id_pixels[imageid]:\n            for i in range(0, len(encorded_pixels), 2):\n                pos_idx = encorded_pixels[i]-1\n                length = encorded_pixels[i+1]\n                label[pos_idx:pos_idx+length] = 255\n\n        label = label.reshape(col, row).transpose()\n        return label\n\n    def get_masks(self,imageid):\n        img_path = os.path.join(\n            self.stage1_data_path, imageid, 'images', imageid+'.png')\n        img = imread(img_path)\n        row, col = img.shape[:2]\n        masks=[]\n        for encorded_pixels in self.id_pixels[imageid]:\n            mask = np.zeros(row*col, dtype=int)\n            for i in range(0, len(encorded_pixels), 2):\n                pos_idx = encorded_pixels[i]-1\n                length = encorded_pixels[i+1]\n                mask[pos_idx:pos_idx+length] = 255\n            mask=mask.reshape(col,row).transpose()\n            masks.append(mask)\n        return masks","execution_count":4,"outputs":[]},{"metadata":{"_uuid":"68a4a277ae05255bbf64f8e1dbdc4fd48d766d36"},"cell_type":"markdown","source":"# Let's decode and show an example"},{"metadata":{"trusted":true,"_uuid":"5cfca6ba44a25f4e7e0e8bad3c813b6f5ba965db"},"cell_type":"code","source":"decoder=CSVDecoder(stage1_csv_path,train=True)\nexample_id = '0d3640c1f1b80f24e94cc9a5f3e1d9e8db7bf6af7d4aba920265f46cadc25e37'\ndecoded=decoder.decode(example_id)\nplt.imshow(decoded)","execution_count":5,"outputs":[]},{"metadata":{"_uuid":"90e7f8744036af535975c359bc09ad1687d51bd7"},"cell_type":"markdown","source":"# pick up a snowman-like object"},{"metadata":{"trusted":true,"_uuid":"8555448a6dd5f3d9a915c7cac9f67100add002a2"},"cell_type":"code","source":"image_labels = measure.label(decoded)\ntarget_label = image_labels==4\nplt.imshow(target_label)","execution_count":6,"outputs":[]},{"metadata":{"_uuid":"e0984d1a7727ee7d51361f80de265aeaa5ae21a8"},"cell_type":"markdown","source":"# Prepare some technique\n- I would like to use watershed alogorithm directly.\n- It does not work what I expected. But somehow I will use it the result with some techniques."},{"metadata":{"trusted":true,"_uuid":"30d69cb6389bb0967774b0500811c19688029f76"},"cell_type":"code","source":"distance = ndimage.distance_transform_edt(target_label)\nlocal_maxi = peak_local_max(distance, indices=False, footprint=np.ones((3, 3)), labels=target_label)\nmarkers = skimage.morphology.label(local_maxi)\nlabels_ws = watershed(-distance, markers, mask=target_label)\nplt.imshow(labels_ws)","execution_count":7,"outputs":[]},{"metadata":{"_uuid":"fb46687a6489992e49b2af2dc1f1a644dfe2a041"},"cell_type":"markdown","source":"# Here is my strategy\n- find contour\n- find point which we call as \"left angle corner\"\n- find the longest sub-contour which connects two left angle corner\n- use elliptic approximation with OpenCV-API along with the sub-contour above"},{"metadata":{"trusted":true,"_uuid":"d26bc65895aaa14348502dcd36829f6564e923b8"},"cell_type":"code","source":"image_labels = measure.label(decoded)\ntarget_label = image_labels==4\n\ncontours = measure.find_contours(target_label,0.5)\ncontour_map=np.zeros(target_label.shape)\n\ncontours.sort(key=lambda x:-len(x))\ncontour=contours[0]\nfor c in contour:\n    contour_map[int(c[0]),int(c[1])]=1\n\nplt.imshow(contour_map)","execution_count":8,"outputs":[]},{"metadata":{"_uuid":"eb522451324896fe38c3bd5fab70646dcba152aa"},"cell_type":"markdown","source":"## find left angle corner"},{"metadata":{"trusted":true,"_uuid":"4190942d6cb15e41b04cc98419bf540cf525d217"},"cell_type":"code","source":"contour=contours[0]\nfor c in contour:\n    contour_map[int(c[0]),int(c[1])]=1\nstep_contour=contour.astype(int)[::5]\ncontour_map/=5\nlength=len(step_contour)\nstep=2\ncnt=0\nfor i in range(0,length,step):\n    cpre=step_contour[(i-step)%length]\n    c = step_contour[i]\n    cnxt=step_contour[(i+step)%length]\n    vpre=(cpre-c)/np.linalg.norm(cpre-c)\n    vnxt=(cnxt-c)/np.linalg.norm(cnxt-c)\n    cos_theta=np.dot(vpre,vnxt)\n    theta=np.arccos(cos_theta)\n    if np.cross(vpre,vnxt) < 0 and np.rad2deg(theta)<160:\n        cnt+=1\n        contour_map[tuple(c)]=1 # this position c is what we call left angle corner\nplt.imshow(contour_map,cmap='gray')","execution_count":9,"outputs":[]},{"metadata":{"_uuid":"086324b1f4a28628cbcdf702d4030a13b8854184"},"cell_type":"markdown","source":"## label contour part1"},{"metadata":{"trusted":true,"_uuid":"14d9682119d6e5f9f7d4f413c42725e329fc245b"},"cell_type":"code","source":"image_labels = measure.label(decoded)\ntarget_label = image_labels==4\ncontours = measure.find_contours(target_label,0.5)\ncontours.sort(key=lambda x:-len(x))\ncontour=contours[0].astype(int)\nstep_contour=contour[::5]\nlabeled_contour_map=np.zeros(target_label.shape)\n\ncontour_label_pair=[]\n\nfor c in contour:\n    nbd_value=[]\n    for i in [-1,0,1]:\n        for j in [-1,0,1]:\n             nbd_value.append(contour_map[(c[0]+i)%target_label.shape[0],(c[1]+j)%target_label.shape[1]])\n\n    labeled_contour_map[tuple(c)]=max(nbd_value)\n    contour_label_pair.append([c, max(nbd_value)])\n    \nplt.imshow(labeled_contour_map,cmap='gray')","execution_count":10,"outputs":[]},{"metadata":{"_uuid":"5dce5de9712e8d326c21d3e6b56fc1d19508ab20"},"cell_type":"markdown","source":"## label contour part2"},{"metadata":{"trusted":true,"_uuid":"d4d12e35f47524e42d1633787a40a037276331d5"},"cell_type":"code","source":"relabeled_contour_map=np.zeros(target_label.shape)\nnew_label=1\ncounter=defaultdict(int)\nfor c_label in contour_label_pair:\n    c,label=c_label[0],c_label[1]\n    if label ==1:\n        new_label+=1\n    counter[new_label]+=1\n    relabeled_contour_map[tuple(c)]=new_label\nplt.imshow(relabeled_contour_map )","execution_count":11,"outputs":[]},{"metadata":{"_uuid":"68869a349668b72d9c27bf7b60b060c85f20e71c"},"cell_type":"markdown","source":"## find the longest contour which connects two left angle corner"},{"metadata":{"trusted":true,"_uuid":"c7b5fe27f06589dee764fdaac5e59e0dd820bbc4"},"cell_type":"code","source":"kmax,vmax=0,0\nfor k,v in counter.items():\n    if vmax < v:\n        vmax=v\n        kmax=k\nplt.imshow(relabeled_contour_map==kmax)","execution_count":12,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fb85f7a7a48246cde86798ec51d1ed01eb17df1e"},"cell_type":"code","source":"labeled_contour_map=relabeled_contour_map\nplt.imshow(labeled_contour_map==kmax)","execution_count":13,"outputs":[]},{"metadata":{"_uuid":"a600d42f404b8b211beb891fc527c55094ef0243"},"cell_type":"markdown","source":"## use fitEllipse of cv2"},{"metadata":{"trusted":true,"_uuid":"47aa8a1ecbec9ec3b3c5e0460b8757f29efad686"},"cell_type":"code","source":"img_gray=(labeled_contour_map==kmax).astype(np.uint8)*255\nret, thresh = cv2.threshold(img_gray, 127, 255,0)\n_, contours,hierarchy = cv2.findContours(thresh,2,1)\n\ndisplayframe=np.zeros(img_gray.shape)\n\nfor ind, cont in enumerate(contours):\n    elps = cv2.fitEllipse(cont)\n    pos,axis,angle=elps\n    mag=0.6\n    axis=(axis[0]*mag,axis[1]*mag)\n    elps=(pos,axis,angle)\n    #Feed elps directly into cv2.ellipse\n    cv2.ellipse(displayframe,elps,(255,0,0),-1)\nplt.figure(figsize=(10,5),dpi=180)\nplt.subplot(1,5,1)\nplt.imshow(labeled_contour_map==kmax)\nplt.subplot(1,5,2)\nplt.imshow(displayframe)\nplt.subplot(1,5,3)\nplt.imshow(target_label)\nplt.subplot(1,5,4)\nfrom copy import copy\nextraced_labels_ws=copy(labels_ws)\nextraced_labels_ws[~displayframe.astype(bool)]=0\nbuff=np.zeros(labels_ws.shape)\nfor i in set(extraced_labels_ws.flatten()):\n    if i==0:\n        continue\n    tmp = labels_ws==i\n    buff+=tmp\nplt.imshow(buff)\nplt.subplot(1,5,5)\nplt.imshow(target_label-buff)","execution_count":14,"outputs":[]},{"metadata":{"_uuid":"7e66c456e860a7e6c20d3b6128b711f6b5f7ce45"},"cell_type":"markdown","source":"# Yes, we have succeeded to separate snow man object :D"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"bb54eb28be16813fa3b238b1a88acfa5928dec23"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"6db84f5af75326e3765cf802ea50b6c6938987cd"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}