{"cells":[{"cell_type":"code","execution_count":null,"metadata":{"collapsed":false},"outputs":[],"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 in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\nimport os\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\n#from subprocess import check_output\n#print(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n\n"},{"cell_type":"markdown","metadata":{},"source":"There are many feature detectors in opencv. I choose ORB because of its speed and robust quality. See below for some\nfunction definition"},{"cell_type":"code","execution_count":null,"metadata":{"collapsed":false},"outputs":[],"source":"# Any results you write to the current directory are saved as output.\ndef im_align_orb(imp1, imp2, nf=10000):\n    \"\"\"\n    :param imp1: image1 file path\n    :param imp2: image2 file path\n    :param nf: max number of ORB key points\n    :return:  transformed image2, so that it can be aligned with image1\n    \"\"\"\n    img1 = cv2.imread(imp1, 0)\n    img2 = cv2.imread(imp2, 0)\n    h2, w2 = img2.shape[:2]\n\n    orb = cv2.ORB_create(nfeatures=nf, WTA_K=2)\n    kp1, des1 = orb.detectAndCompute(img1, None)\n    kp2, des2 = orb.detectAndCompute(img2, None)\n\n    # create BFMatcher object\n    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)\n\n    # Match descriptors.\n    matches = bf.knnMatch(des1, des2, 2)\n\n    # Sort them in the order of their distance.\n    # matches_ = sorted(matches, key=lambda x: x.distance)[:5000]\n    # print([m.distance for m in matches_])\n\n    matches_ = []\n    for m in matches:\n        if len(m) == 2 and m[0].distance < m[1].distance * 0.75:\n            matches_.append((m[0].trainIdx, m[0].queryIdx))\n\n    #print(\"len(kp1), len(kp2), len(matches_)\")\n\n    kp1_ = np.float32([kp1[m[1]].pt for m in matches_]).reshape(-1, 1, 2)\n    kp2_ = np.float32([kp2[m[0]].pt for m in matches_]).reshape(-1, 1, 2)\n\n    H, mask = cv2.findHomography(kp2_, kp1_, cv2.RANSAC, 1.0)\n\n    h1, w1 = img1.shape[:2]\n\n    img2 = cv2.warpPerspective(cv2.imread(imp2), H, (w1, h1))\n    return img2\n\ndef align_set_by_id(setid, isTrain=True, nFeatures=20000):\n    \"\"\"\n    :param setid:\n    :param isTrain:\n    :return:\n    \"\"\"\n    train_path = '../input/train_sm/'\n    test_path = '../input/test_sm/'\n\n    if isTrain == True:\n        image_path = train_path\n        fn1 = train_path + \"set\" + str(setid) + \"_1.jpeg\"\n        outputpath = \"./train_output\"\n    else:\n        image_path = test_path\n        fn1 = test_path + \"set\" + str(setid) + \"_1.jpeg\"\n        outputpath = \"./test_output/\" \n    \n    result=list()\n    result.append(cv2.cvtColor(cv2.imread(fn1), cv2.COLOR_BGR2RGB))\n    for id in [2, 3, 4, 5]:\n        fn2 = image_path + \"set\" + str(setid) + \"_\" + str(id) + \".jpeg\"\n        print(\"fn1=%s, fn2=%s\" % (os.path.basename(fn1), os.path.basename(fn2)))\n        im = im_align_orb(fn1, fn2, nFeatures)\n        #Note: kaggle script seems can't save output image? \n        #cv2.imwrite(outputpath + os.path.basename(fn2), im)\n        result.append(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))\n\n    #Note: kaggle script seems can't save output image? \n    #cv2.imwrite(outputpath + os.path.basename(fn1), cv2.imread(fn1))\n    \n    return result"},{"cell_type":"markdown","metadata":{},"source":"In above cell I have already defined some key functions. Now I can use align_set_by_id() function to \nalign all images for specified set. Please note, here I use ORB feature detector which has one parameter\nnFeatures. It means the max number of features to query. According to my experiment, for current train \nand test images, you'd better set it to 15000~20000 to get better balance between quality and speed. \n\nFor example:"},{"cell_type":"code","execution_count":null,"metadata":{"collapsed":false},"outputs":[],"source":"setimages=align_set_by_id(5, nFeatures=15000)"},{"cell_type":"code","execution_count":null,"metadata":{"collapsed":false},"outputs":[],"source":"from PIL import Image \n\nplt.rcParams['figure.figsize'] = (16.0,16.0)\n\nplt.subplot(321).set_title('image1'), plt.imshow(setimages[0]),plt.axis('off')\nplt.subplot(323).set_title('image2'), plt.imshow(setimages[1]),plt.axis('off')\nplt.subplot(324).set_title('image3'), plt.imshow(setimages[2]),plt.axis('off')\nplt.subplot(325).set_title('image4'), plt.imshow(setimages[3]),plt.axis('off')\nplt.subplot(326).set_title('image5'), plt.imshow(setimages[4]),plt.axis('off')\n\nplt.show()\n\n"},{"cell_type":"markdown","metadata":{},"source":"I have already defined another function align_all_set() so that we can align all sets in batch mode.\nIn your local computer you can run this function to generate all aligned images (very slow).\n\nSee below:"},{"cell_type":"code","execution_count":null,"metadata":{"collapsed":false},"outputs":[],"source":"def align_all_set(path, isTrain=True):\n    allfiles = os.listdir(path)\n    allfiles = [os.path.basename(file) for file in allfiles if file.startswith('set')]\n    allsets = np.unique([f.split(\"_\")[0].replace(\"set\", \"\") for f in allfiles])\n\n    os.makedirs(path + \"/output\", exist_ok=True)\n\n    for s in allsets:\n        align_set_by_id(s, isTrain, nFeatures=20000)"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":0}