{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Project texture\n\nCredit: A Grigis\n\nConvert a texture onto a spherical surface into an image by evenly\nresampling the spherical surface with respect to sin(e) and a, where e\nand a are elevation and azimuth, respectively, and vice versa.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import torch\nimport numpy as np\nfrom surfify import utils\nfrom surfify import datasets\nfrom surfify import plotting\nimport surfify.nn.functional as F\nimport matplotlib.pyplot as plt"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Load data\n\nFirst we load the classification dataset (with 3 classes).\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "ico_order = 3\nn_classes = 3\nstandard_ico = False\nico_vertices, ico_triangles = utils.icosahedron(\n    order=ico_order, standard_ico=standard_ico)\nn_vertices = len(ico_vertices)\n_, labels = datasets.make_classification(\n    ico_vertices, n_samples=40, n_classes=n_classes, scale=1, seed=42)\nprint(\"Surface:\", ico_vertices.shape, ico_triangles.shape)\nprint(\"Labels:\", labels.shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 3-D surface to 2-D grid projection\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "proj_texture = utils.text2grid(ico_vertices, labels)\nprint(\"Proj texture:\", proj_texture.shape)\nplt.figure()\nplt.imshow(proj_texture.T, origin=\"lower\")\nplt.axis(\"off\")\nplt.title(\"Nearest\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 2-D grid to 3-D surface projection\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "texture = utils.grid2text(ico_vertices, proj_texture)\nprint(\"Texture:\", texture.shape)\nplotting.plot_trisurf(ico_vertices, ico_triangles, labels, is_label=True)\nplotting.plot_trisurf(ico_vertices, ico_triangles, texture, is_label=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Uniformly distributed locations\n\nUsing the sin of the elevation enables us to have resampled locations\nalmost uniformly distributed.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "def scatter_density(x, y, labelx, labely):\n    \"\"\" Display scatter plot with x- and y- densities.\n    \"\"\"\n    left, width = 0.1, 0.65\n    bottom, height = 0.1, 0.65\n    spacing = 0.005\n    rect_scatter = [left, bottom, width, height]\n    rect_histx = [left, bottom + height + spacing, width, 0.2]\n    rect_histy = [left + width + spacing, bottom, 0.2, height]\n\n    plt.figure(figsize=(8, 8))\n    ax_scatter = plt.axes(rect_scatter)\n    ax_scatter.tick_params(direction=\"in\", top=True, right=True)\n    ax_scatter.set_xlabel(labelx)\n    ax_scatter.set_ylabel(labely)\n    ax_histx = plt.axes(rect_histx)\n    ax_histx.axis(\"off\")\n    ax_histy = plt.axes(rect_histy)\n    ax_histy.axis(\"off\")\n\n    ax_scatter.scatter(x, y)\n\n    bins = 20\n    ax_histx.hist(x, bins=bins)\n    ax_histy.hist(y, bins=bins, orientation=\"horizontal\")\n    ax_histx.set_xlim(ax_scatter.get_xlim())\n    ax_histy.set_ylim(ax_scatter.get_ylim())\n\n\nazimuth, elevation, radius = utils.cart2sph(*ico_vertices.T)\nsin_elevation = np.sin(elevation)\nscatter_density(azimuth, elevation, labelx=\"a\", labely=\"e\")\nscatter_density(azimuth, sin_elevation, labelx=\"a\", labely=\"sin(e)\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Integration in deep neural network\n\nSince a spherical patterns are circularly continuous with respect to the\nazimuth, we need to apply circular padding to the boundaries of azimuth for\nthe flattened 2-D map but applied zero padding to the boundaries of\nevaluation.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "proj_texture = np.expand_dims(proj_texture, axis=(0, 1)).astype(np.float32)\nproj_texture = torch.from_numpy(proj_texture)\nprint(\"Proj texture:\", proj_texture.shape)\npad_texture = F.circular_pad(proj_texture, pad=(1, 1))\nprint(\"Padd texture:\", pad_texture.shape)\nconv = torch.nn.Conv2d(\n    in_channels=1, out_channels=3, kernel_size=3, stride=1, padding=0)\nconv_texture = conv(pad_texture)\nprint(\"Conv texture:\", conv_texture.shape)\n\nplt.show()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.6.12"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}