{"nbformat_minor": 1, "metadata": {"language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "pygments_lexer": "ipython3", "name": "python", "nbconvert_exporter": "python", "file_extension": ".py", "version": "3.6.4", "mimetype": "text/x-python"}, "kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}}, "nbformat": 4, "cells": [{"source": ["# Overview\n", "A notebook which tries to classify the camera based the spatial resolution in the images (compared to a noise background) see [10.1002/pssa.200675685](http://onlinelibrary.wiley.com/doi/10.1002/pssa.200675685/full)"], "cell_type": "markdown", "metadata": {"_cell_guid": "033e27a4-d600-4bf1-adf9-d9a0ba316f3e", "_uuid": "1a48ea0f604b56754cd25a290a0f37a8dfd5623c"}}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "8e119507-463b-4349-bf53-a0d70f59d0e1", "_uuid": "c17b461b803801610e2eabc2e6f492301f9084c6"}, "source": ["import numpy as np # linear algebra\n", "import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n", "import os\n", "from skimage.io import imread # read image\n", "from PIL import Image \n", "# imread fails on some of the tiffs so we use PIL\n", "pil_imread = lambda c_file: np.array(Image.open(c_file)) \n", "from skimage.exposure import equalize_adapthist\n", "from glob import glob\n", "\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "941710b6-33b6-4c40-89c5-c30452eeba7e", "_uuid": "a7e4afe4d4802460f236159cce4b73b031932c77"}, "source": ["list_train = glob(os.path.join('..', 'input', 'train', '*', '*.jpg'))\n", "print('Train Files found', len(list_train), 'first file:', list_train[0])\n", "list_test = glob(os.path.join('..', 'input', '*', '*.tif'))\n", "print('Test Files found', len(list_test), 'first file:', list_test[0])"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "7c57e7f2-fab6-4a3a-90f7-2ce782a2d71d", "_uuid": "a9c632622efc366a3d2b44b3b5b114f879072a18"}, "source": ["from sklearn.preprocessing import LabelEncoder\n", "def get_class_from_path(filepath):\n", "    return os.path.dirname(filepath).split(os.sep)[-1]\n", "full_train_df = pd.DataFrame([{'path': x, 'category': get_class_from_path(x)} for x in list_train])\n", "cat_encoder = LabelEncoder()\n", "cat_encoder.fit(full_train_df['category'])\n", "nclass = cat_encoder.classes_.shape[0]\n", "full_train_df.sample(3)"]}, {"source": ["# Camera Distribution\n", "A quick look at how the training data are distributed to get a feeling for how common each camera type is. To make sure the training data isn't all too skewed"], "cell_type": "markdown", "metadata": {"_cell_guid": "a488fbfe-53f2-4091-847b-de9b91ba412a", "_uuid": "b563f2c97d0d3a106c338dd5f63669cc0b881ed8"}}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "775aaa10-4bcc-45b3-a13d-79e6de2f2e4e", "_uuid": "5166e06773a0cce7614496c51d9cf48d9e4c2d24"}, "source": ["fig, ax1 = plt.subplots(1,1,figsize = (8, 6))\n", "ax1.hist(cat_encoder.transform(full_train_df['category']), np.arange(nclass+1))\n", "ax1.set_xticks(np.arange(nclass))\n", "_ = ax1.set_xticklabels(cat_encoder.classes_, rotation = 45)"]}, {"source": ["## Preprocessing\n", "Here is some basic preprocessing code to try and correct for things we are not interested in light illumination, and low frequency scene information"], "cell_type": "markdown", "metadata": {"_cell_guid": "4ea59577-eb9c-4cb2-9451-bfd4dd7d373c", "_uuid": "250ea42bf046505d50597fb22f48fd11c50219a7"}}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "e533b8e1-5c20-4bbf-98ac-f973f8e021a0", "_uuid": "039600ab3e17e88347f65d5c455ac30cfa99e7b0"}, "source": ["def imread_and_normalize(im_path):\n", "    img_data = pil_imread(im_path)\n", "    return img_data/255.0\n", "\n", "test_img = imread_and_normalize(full_train_df['path'].values[0])\n", "plt.imshow(test_img)"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "1be541e3-112d-424c-b51f-ad3bf59e875b", "_uuid": "b3cccf2c91d2f5290d795a2210d344159e2946f2"}, "source": ["from numpy.fft import fft2\n", "from scipy import signal\n", "def gen_nd_psd(in_img, n_pts):\n", "    out_f = np.linspace(0, 0.5, n_pts)\n", "    out_psd = np.zeros((out_f.shape[0], 3))\n", "    for i in range(in_img.shape[2]):\n", "        for j in range(in_img.shape[1]):\n", "            f, nPxx_den = signal.periodogram(in_img[:,j, i], 1, \n", "                                            'flattop', \n", "                                            scaling='density')\n", "            if j==0:\n", "                Pxx_den = nPxx_den\n", "            else:\n", "                Pxx_den += nPxx_den\n", "        Pxx_den = Pxx_den/in_img.shape[1]\n", "        out_psd[:, i] = np.interp(out_f,f, Pxx_den)\n", "    return out_f, out_psd"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "a654c76d-1719-4841-a078-a04893796daa", "_uuid": "31133e0341dc20f076da3de5a075fdf679e939c4"}, "source": ["%%time\n", "out_f, out_psd = gen_nd_psd(test_img, 100)"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "54120bd6-085a-48d6-a13a-d0b7b6872e04", "_uuid": "204d7d6ddaacd2240696a4ae33fc9ac272b6a82b"}, "source": ["fig, rgb_ax = plt.subplots(1,3, figsize = (12, 3))\n", "for i, c_ax in enumerate(rgb_ax):\n", "    c_ax.semilogy(out_f, out_psd[:, i], '.')\n", "    c_ax.set_ylim([1e-9, 1e2])\n", "    c_ax.set_title('RGB'[i]+' color information')\n", "    c_ax.set_xlabel('frequency [Hz]')\n", "    c_ax.set_ylabel('PSD [V**2/Hz]')"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "bdaa6cad-a0d9-4b67-8404-d2ea6b3598a3", "_uuid": "29c03f560d2b319ad5e6666c755946fe5fa3cba7"}, "source": ["plt.plot(np.log10(out_psd))"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "e84fa3cf-9add-4c9a-98d6-e91cac41cdc3", "_uuid": "b8b013eeb738407bfa40d9e70180d13ccfe8f519"}, "source": ["%%time\n", "subset_df = full_train_df.groupby('category').apply(lambda x: x.sample(1)).reset_index(drop = True)\n", "subset_df['img'] = subset_df['path'].map(lambda x: imread_and_normalize(x))\n", "subset_df['psd'] = subset_df['img'].map(lambda x: gen_nd_psd(x, 100)[1])"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "c31172d6-25e3-4bd0-8f68-d3f00788930b", "_uuid": "bb8bd7b67d1bbf589f6642c369ac28aa81de07c9"}, "source": ["fig, c_axs = plt.subplots(2, subset_df.shape[0], figsize = (24, 6))\n", "for (c_ax, m_ax), (_, c_row) in zip(c_axs.T, subset_df.iterrows()):\n", "    c_ax.imshow(c_row['img'])\n", "    c_ax.set_title(c_row['category'])\n", "    c_ax.axis('off')\n", "    m_ax.plot(np.log10(c_row['psd']))\n", "    m_ax.set_ylim(-5, 0)"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "817a5c40-9ebb-4820-ab1c-6aa946450c5e", "_uuid": "b8b8d952e1788a4eefd9512ece0dc717660de623"}, "source": ["fig, ax = plt.subplots(1,1, figsize = (6, 6))\n", "for _, c_row in subset_df.iterrows():\n", "    ax.plot(np.log10(c_row['psd'][:, 0]), label = c_row['category'])\n", "ax.legend()"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "b2e3fdf7-3232-46f7-bb6e-95956d91c09a", "_uuid": "329c9e0184124de50d1c68f81456a410185c65c0"}, "source": ["fig, ax = plt.subplots(1,1, figsize = (6, 6))\n", "for _, c_row in subset_df.iterrows():\n", "    ax.plot(np.log10(c_row['psd'][10:80, 0]), label = c_row['category'])\n", "ax.legend()"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "7c0bfe63-629d-4169-8635-a5c79481da32", "_uuid": "33d90eca35fdfb61df9214986ecd25f0597a34de"}, "source": ["%%time\n", "bigger_subset_df = full_train_df.groupby('category').apply(lambda x: x.sample(30)).reset_index(drop = True)\n", "bigger_subset_df['img'] = bigger_subset_df['path'].map(lambda x: imread_and_normalize(x))\n", "bigger_subset_df['psd'] = bigger_subset_df['img'].map(lambda x: gen_nd_psd(x, 100)[1])"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "eadbb3e3-8796-4788-bbdb-af33abc6624f", "_uuid": "8d914bbd80be00cbb14e0d9bc9a9cdc3929e7665"}, "source": ["d_gen = generate_even_batch(full_train_df)\n", "for _, (x, y) in zip(range(1), d_gen):\n", "    print(x.shape, y.shape)"]}, {"source": ["# Build Model\n", "Here we make a model for processing the snippets"], "cell_type": "markdown", "metadata": {"_cell_guid": "d9d73db0-fc4c-449b-9ec6-865688540797", "_uuid": "68335a88200a19c6754224c074a5fd56803af84d"}}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "23c1d5e9-0202-4905-b790-aba502e34ccc", "_uuid": "cdcc74a8f7f8eb58e9577353a250edb9b1151b68"}, "source": []}, {"source": ["# Training Testing Split\n", "Split the groups apart to have an untainted metric of the success\n"], "cell_type": "markdown", "metadata": {"_cell_guid": "26bcaba6-cecf-4913-908a-ff9d2ef468a7", "_uuid": "d47f14aa01ef7656e9c2a6f276f30f3300e21f3a"}}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "824d617b-ed40-46e5-8658-b4ca3d390928", "_uuid": "f012e4bfb32530ea42bd6afc0e34534be5cdc275"}, "source": ["%%time\n", "from sklearn.model_selection import train_test_split\n", "train_df, test_df = train_test_split(full_train_df, \n", "                                     test_size = 0.15,\n", "                                    random_state = 2018,\n", "                                    stratify = full_train_df['category'])\n", "print('Train', train_df.shape[0], 'Test', test_df.shape[0])\n", "train_gen = generate_even_batch(train_df, 3, chunk_count = 20)\n", "test_gen = generate_even_batch(test_df, 10, chunk_count = 30)\n", "# cache the test_gen_data\n", "(test_x, test_y) = next(test_gen)\n", "print('Test Data', test_x.shape)"]}, {"source": ["# Predict on output\n", "We run the model on the full test image, one at a time, and save the category"], "cell_type": "markdown", "metadata": {"_cell_guid": "05b97451-491b-456c-a1a9-55b404274d9b", "_uuid": "ee2d9cd9418aba722fbfd9cc019f0c3cc0d8f896"}}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "9c03ee90-34a2-488d-9d11-fa24b3cc810a", "_uuid": "7e80ba17eb1285184618d900df76035847d946bc"}, "source": ["from tqdm import tqdm\n", "out_dict_list = []\n", "for c_file in tqdm(list_test):\n", "    ck_data = read_chunk(c_file, n_chunk = 100)\n", "    ck_pred = model.predict(ck_data)\n", "    # take the average prediction\n", "    mean_vec = np.mean(ck_pred,0)\n", "    out_dict_list += [{\n", "        'fname': os.path.basename(c_file),\n", "        'camera': np.argmax(mean_vec,0)\n", "    }]  "]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "3078ba99-1e6e-4f72-8f95-cd579236a930", "_uuid": "5d11a7d9c02cf6508332ec5d19db2f5848c46f79"}, "source": ["df = pd.DataFrame(out_dict_list)\n", "df['camera'] = df['camera'].map(cat_encoder.inverse_transform)\n", "df[['fname', 'camera']].to_csv(\"submission.csv\", index=False)\n", "df.sample(3)"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "26cb2059-1f98-4182-8076-38bc97a55195", "_uuid": "31775597358630adb28c5874f260d672cb449747"}, "source": ["fig, ax1 = plt.subplots(1,1,figsize = (8, 6))\n", "ax1.hist(cat_encoder.transform(df['camera']), np.arange(nclass+1))\n", "ax1.set_xticks(np.arange(nclass)+0.5)\n", "_ = ax1.set_xticklabels(cat_encoder.classes_, rotation = 90)"]}, {"execution_count": null, "cell_type": "code", "outputs": [], "metadata": {"collapsed": true, "_cell_guid": "75d80c11-6e0f-4fb4-bc6a-1bce0e302fd3", "_uuid": "91727a7713a92be6c3c0f312d848216cce202168"}, "source": []}]}