{"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":"Streamlining the idea of @remekkinas: https://www.kaggle.com/remekkinas/step-2-find-numbers-no-model-required","metadata":{}},{"cell_type":"code","source":"!pip install imutils -q","metadata":{"execution":{"iopub.status.busy":"2022-03-10T20:49:18.183141Z","iopub.execute_input":"2022-03-10T20:49:18.183496Z","iopub.status.idle":"2022-03-10T20:49:32.570978Z","shell.execute_reply.started":"2022-03-10T20:49:18.183407Z","shell.execute_reply":"2022-03-10T20:49:32.570214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nimport os\nimport cv2\nfrom skimage import measure\nimport glob\nimport imutils\nimport matplotlib.pyplot as plt\n\nfrom imutils import contours\nfrom PIL import Image as Img\nfrom IPython.display import Image\n\nfrom joblib import Parallel, delayed\nfrom tqdm import tqdm_notebook as tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-03-10T20:49:32.573932Z","iopub.execute_input":"2022-03-10T20:49:32.574181Z","iopub.status.idle":"2022-03-10T20:49:34.182574Z","shell.execute_reply.started":"2022-03-10T20:49:32.574153Z","shell.execute_reply":"2022-03-10T20:49:34.181777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG:\n    train_path = '../input/ultramnistblack/train/'\n    test_path = '../input/ultramnistblack/test/'\n    train_out_path = 'train_patches/'\n    test_out_path = 'test_patches/'\n    size = 256\n    \nif not os.path.exists(CFG.train_out_path):\n    os.makedirs(CFG.train_out_path)\nif not os.path.exists(CFG.test_out_path):\n    os.makedirs(CFG.test_out_path)\n    ","metadata":{"execution":{"iopub.status.busy":"2022-03-10T20:49:34.183873Z","iopub.execute_input":"2022-03-10T20:49:34.184117Z","iopub.status.idle":"2022-03-10T20:49:34.190350Z","shell.execute_reply.started":"2022-03-10T20:49:34.184085Z","shell.execute_reply":"2022-03-10T20:49:34.189412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Our workhorse function: for a given image, store the patches extracted via OpenCV methods","metadata":{}},{"cell_type":"code","source":"# create patches for a given image - adapted from https://www.kaggle.com/remekkinas/step-2-find-numbers-no-model-required\ndef create_patches(fname, outdir):\n    \n    image = cv2.imread(fname, 0)\n    blurred = cv2.GaussianBlur(image, (11, 11), 0)\n    thresh = cv2.threshold(blurred, 200, 255, cv2.THRESH_BINARY)[1]\n    thresh = cv2.erode(thresh, None, iterations=2)\n    thresh = cv2.dilate(thresh, None, iterations=4)\n\n    labels = measure.label(thresh,background = 0)\n    mask = np.zeros(thresh.shape, dtype=\"uint8\")\n    for label in np.unique(labels):\n        if label == 0:\n            continue\n\n        labelMask = np.zeros(thresh.shape, dtype=\"uint8\")\n        labelMask[labels == label] = 255\n        numPixels = cv2.countNonZero(labelMask)\n        if numPixels > 300:\n            mask = cv2.add(mask, labelMask)\n\n    bbox_list = []\n\n    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n    cnts = imutils.grab_contours(cnts)\n    cnts = contours.sort_contours(cnts)[0]\n    # print(f'Found {len(cnts)} contours / numbers')\n    backtorgb = cv2.cvtColor(image.astype('float32'), cv2.COLOR_GRAY2RGB)\n\n    for (i, c) in enumerate(cnts):\n        (x, y, w, h) = cv2.boundingRect(c)\n        bbox_list.append([x, y, w, h])\n        cv2.rectangle(backtorgb, (x,y), (x+w, y+h), (255,0,0), 5)\n\n    #print(f'BBoxes coordinates: {bbox_list}')\n    # display(Img.fromarray(backtorgb.astype(np.uint8)).resize((480,480)))\n\n    for (i, bbox) in enumerate(bbox_list):\n        bbox_img = image[bbox[1]:bbox[1]+bbox[3], bbox[0]:bbox[0]+bbox[2]]\n        bbox_resized = cv2.resize(bbox_img, (CFG.size, CFG.size), interpolation = cv2.INTER_AREA)\n    #    display(Img.fromarray((bbox_resized).astype(np.uint8)))\n        cv2.imwrite(outdir + fname.split('/')[-1][:-5] + '_p'+ str(i) + '.jpeg', bbox_resized)\n    \n    return 0","metadata":{"execution":{"iopub.status.busy":"2022-03-10T20:49:34.191884Z","iopub.execute_input":"2022-03-10T20:49:34.192233Z","iopub.status.idle":"2022-03-10T20:49:34.209683Z","shell.execute_reply.started":"2022-03-10T20:49:34.192188Z","shell.execute_reply":"2022-03-10T20:49:34.208654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create the lists for training and test files\ntrain_list = glob.glob(os.path.join(CFG.train_path,  '*.jpeg'))\ntest_list = glob.glob(os.path.join(CFG.test_path,  '*.jpeg'))","metadata":{"execution":{"iopub.status.busy":"2022-03-10T20:49:34.212289Z","iopub.execute_input":"2022-03-10T20:49:34.212579Z","iopub.status.idle":"2022-03-10T20:49:35.519950Z","shell.execute_reply.started":"2022-03-10T20:49:34.212542Z","shell.execute_reply":"2022-03-10T20:49:35.518972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Parallelize the extraction for training set patches","metadata":{}},{"cell_type":"code","source":"res1 = Parallel(n_jobs=8, backend='threading')(delayed(\n    create_patches)(i, CFG.train_out_path) for i in tqdm(train_list[:1000], total=len(train_list)))","metadata":{"execution":{"iopub.status.busy":"2022-03-10T20:11:15.141166Z","iopub.execute_input":"2022-03-10T20:11:15.141423Z","iopub.status.idle":"2022-03-10T20:11:18.862857Z","shell.execute_reply.started":"2022-03-10T20:11:15.141394Z","shell.execute_reply":"2022-03-10T20:11:18.862055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As well as test set ones","metadata":{}},{"cell_type":"code","source":"res2 = Parallel(n_jobs=8, backend='threading')(delayed(\n    create_patches)(i, CFG.test_out_path) for i in tqdm(test_list[:1000], total=len(test_list)))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!zip -r patches.zip ./train_patches/ ./test_patches/","metadata":{"execution":{"iopub.status.busy":"2022-03-10T20:12:10.620333Z","iopub.execute_input":"2022-03-10T20:12:10.621064Z","iopub.status.idle":"2022-03-10T20:12:11.365336Z","shell.execute_reply.started":"2022-03-10T20:12:10.621028Z","shell.execute_reply":"2022-03-10T20:12:11.364317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Once you get patches of sufficient quality, the problem boils down to regular MNIST ;-) ","metadata":{}}]}