diff --git a/interactive_viewer.ipynb b/interactive_viewer.ipynb
index c5d997c..7cd3bc4 100644
--- a/interactive_viewer.ipynb
+++ b/interactive_viewer.ipynb
@@ -1,310 +1,225 @@
{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {
- "colab_type": "text",
- "id": "view-in-github"
- },
- "source": [
- "
"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {
- "colab": {},
- "colab_type": "code",
- "id": "iuV1r5o4WBcc"
- },
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "36893a71327842069312e51a1612a0bf",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "FileUpload(value={}, description='Upload')"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "name": "interactive_viewer.ipynb",
+ "provenance": [],
+ "collapsed_sections": [],
+ "include_colab_link": true
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "name": "python3"
}
- ],
- "source": [
- "##### Copyright 2020 Google LLC. All Rights Reserved.\n",
- "\n",
- "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
- "# you may not use this file except in compliance with the License.\n",
- "# You may obtain a copy of the License at\n",
- "#\n",
- "# https://www.apache.org/licenses/LICENSE-2.0\n",
- "#\n",
- "# Unless required by applicable law or agreed to in writing, software\n",
- "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
- "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
- "# See the License for the specific language governing permissions and\n",
- "# limitations under the License.\n",
- "\n",
- "# Load an image\n",
- "import ipywidgets as widgets\n",
- "from IPython.display import display\n",
- "uploader = widgets.FileUpload(multiple=False)\n",
- "display(uploader)"
- ]
},
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {
- "cellView": "form",
- "colab": {},
- "colab_type": "code",
- "id": "cXfefXlKOYQl"
- },
- "outputs": [
+ "cells": [
{
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "bcf3aaa9ad2046609f7e08e4bdf3d766",
- "version_major": 2,
- "version_minor": 0
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "view-in-github",
+ "colab_type": "text"
},
- "text/plain": [
- "Button(description='Default', style=ButtonStyle())"
+ "source": [
+ "
"
]
- },
- "metadata": {},
- "output_type": "display_data"
},
{
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "79e8241b797340238431e34063f386af",
- "version_major": 2,
- "version_minor": 0
+ "cell_type": "code",
+ "metadata": {
+ "colab_type": "code",
+ "id": "iuV1r5o4WBcc",
+ "colab": {}
},
- "text/plain": [
- "HBox(children=(Button(description=\"Otsu's Method\", style=ButtonStyle()), Button(description='MET', style=Butto…"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
+ "source": [
+ "##### Copyright 2020 Google LLC. All Rights Reserved.\n",
+ "\n",
+ "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
+ "# you may not use this file except in compliance with the License.\n",
+ "# You may obtain a copy of the License at\n",
+ "#\n",
+ "# https://www.apache.org/licenses/LICENSE-2.0\n",
+ "#\n",
+ "# Unless required by applicable law or agreed to in writing, software\n",
+ "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
+ "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
+ "# See the License for the specific language governing permissions and\n",
+ "# limitations under the License.\n",
+ "\n",
+ "# Load an image\n",
+ "import ipywidgets as widgets\n",
+ "from IPython.display import display\n",
+ "uploader = widgets.FileUpload(multiple=False)\n",
+ "display(uploader)"
+ ],
+ "execution_count": null,
+ "outputs": []
},
{
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "b1319d8b388b4fdd857a4fa95e4dd214",
- "version_major": 2,
- "version_minor": 0
+ "cell_type": "code",
+ "metadata": {
+ "id": "cXfefXlKOYQl",
+ "colab_type": "code",
+ "colab": {},
+ "cellView": "form"
},
- "text/plain": [
- "Output()"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "b0a9eb2938804cc598954f82684aa39e",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "interactive(children=(FloatLogSlider(value=961851.0, description='nu', max=30.0, min=-30.0, step=1.0), FloatLo…"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
+ "source": [
+ "#@title An interactive viewer for tuning hyperparameters\n",
+ "\n",
+ "# Load the image\n",
+ "from PIL import Image\n",
+ "import io\n",
+ "import numpy as np\n",
+ "\n",
+ "image_data = list(uploader.value.values())[0]['content']\n",
+ "im = np.array(Image.open(io.BytesIO(image_data)))\n",
+ "\n",
+ "# A fast numpy reference implementation of GHT, as per\n",
+ "# \"A Generalization of Otsu's Method and Minimum Error Thresholding\"\n",
+ "# Jonathan T. Barron, ECCV, 2020\n",
+ "\n",
+ "csum = lambda z: np.cumsum(z)[:-1]\n",
+ "dsum = lambda z: np.cumsum(z[::-1])[-2::-1]\n",
+ "argmax = lambda x, f: np.mean(x[:-1][f == np.max(f)]) # Use the mean for ties.\n",
+ "clip = lambda z: np.maximum(1e-30, z)\n",
+ "\n",
+ "def preliminaries(n, x):\n",
+ " \"\"\"Some math that is shared across multiple algorithms.\"\"\"\n",
+ " assert np.all(n >= 0)\n",
+ " x = np.arange(len(n), dtype=n.dtype) if x is None else x\n",
+ " assert np.all(x[1:] >= x[:-1])\n",
+ " w0 = clip(csum(n))\n",
+ " w1 = clip(dsum(n))\n",
+ " p0 = w0 / (w0 + w1)\n",
+ " p1 = w1 / (w0 + w1)\n",
+ " mu0 = csum(n * x) / w0\n",
+ " mu1 = dsum(n * x) / w1\n",
+ " d0 = csum(n * x**2) - w0 * mu0**2\n",
+ " d1 = dsum(n * x**2) - w1 * mu1**2\n",
+ " return x, w0, w1, p0, p1, mu0, mu1, d0, d1\n",
+ "\n",
+ "def GHT(n, x=None, nu=0, tau=0, kappa=0, omega=0.5, prelim=None):\n",
+ " assert nu >= 0\n",
+ " assert tau >= 0\n",
+ " assert kappa >= 0\n",
+ " assert omega >= 0 and omega <= 1\n",
+ " x, w0, w1, p0, p1, _, _, d0, d1 = prelim or preliminaries(n, x)\n",
+ " v0 = clip((p0 * nu * tau**2 + d0) / (p0 * nu + w0))\n",
+ " v1 = clip((p1 * nu * tau**2 + d1) / (p1 * nu + w1))\n",
+ " f0 = -d0 / v0 - w0 * np.log(v0) + 2 * (w0 + kappa * omega) * np.log(w0)\n",
+ " f1 = -d1 / v1 - w1 * np.log(v1) + 2 * (w1 + kappa * (1 - omega)) * np.log(w1)\n",
+ " return argmax(x, f0 + f1), f0 + f1\n",
+ "\n",
+ "def im2hist(im, zero_extents=False):\n",
+ " # Convert an image to grayscale, bin it, and optionally zero out the first and last bins.\n",
+ " max_val = np.iinfo(im.dtype).max\n",
+ " x = np.arange(max_val+1)\n",
+ " e = np.arange(-0.5, max_val+1.5)\n",
+ " assert len(im.shape) in [2, 3]\n",
+ " im_bw = np.amax(im[...,:3], -1) if len(im.shape) == 3 else im\n",
+ " n = np.histogram(im_bw, e)[0]\n",
+ " if zero_extents:\n",
+ " n[0] = 0\n",
+ " n[-1] = 0\n",
+ " return n, x, im_bw\n",
+ "\n",
+ "# Precompute a histogram and some integrals.\n",
+ "n, x, im_bw = im2hist(im)\n",
+ "prelim = preliminaries(n, x)\n",
+ "\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "default_nu = np.sum(n)\n",
+ "default_tau = np.sqrt(1/12)\n",
+ "default_kappa = np.sum(n)\n",
+ "default_omega = 0.5\n",
+ "\n",
+ "_nu = default_nu\n",
+ "_tau = default_tau\n",
+ "_kappa = default_kappa\n",
+ "_omega = default_omega\n",
+ "\n",
+ "continuous_update = True\n",
+ "nu_slider = widgets.FloatLogSlider(min=-30, max=30, value=_nu, continuous_update=continuous_update)\n",
+ "tau_slider = widgets.FloatLogSlider(min=-30, max=30, value=_tau, continuous_update=continuous_update)\n",
+ "kappa_slider = widgets.FloatLogSlider(min=-30, max=30, value=_kappa, continuous_update=continuous_update)\n",
+ "omega_slider = widgets.FloatSlider(min=0, max=1, value=_omega, step=0.01, continuous_update=continuous_update)\n",
+ "\n",
+ "def render():\n",
+ " global _nu, _tau, _kappa, _omega\n",
+ " t, score = GHT(n, x, _nu, _tau, _kappa, _omega, prelim)\n",
+ "\n",
+ " plt.figure(0, figsize=(16,5))\n",
+ " plt.subplot(1,3,1)\n",
+ " plt.imshow(im, cmap='gray')\n",
+ " plt.axis('off')\n",
+ "\n",
+ " plt.subplot(1,3,2)\n",
+ " plt.imshow(im_bw > t, cmap='gray', vmin=0, vmax=1)\n",
+ " plt.gca().set_xticks([])\n",
+ " plt.gca().set_yticks([])\n",
+ "\n",
+ " plt.subplot(1,3,3)\n",
+ " normalize = lambda x : (x - np.min(score)) * np.max(n) / (np.max(score) - np.min(score))\n",
+ " plt.plot((x[:-1] + x[1:])/2, normalize(score))\n",
+ " plt.scatter(t, normalize(score[int(t)]))\n",
+ " plt.bar(x, n, width=1)\n",
+ " plt.gca().set_yticks([]);\n",
+ "\n",
+ "def update(nu=None, tau=None, kappa=None, omega=None):\n",
+ " global _nu, _tau, _kappa, _omega\n",
+ " _nu = nu or _nu\n",
+ " _tau = tau or _tau\n",
+ " _kappa = kappa or _kappa\n",
+ " _omega = omega or _omega\n",
+ "\n",
+ "def reset(nu=None, tau=None, kappa=None, omega=None):\n",
+ " global nu_slider, tau_slider, kappa_slider, omega_slider\n",
+ " if nu:\n",
+ " nu_slider.value = nu\n",
+ " if tau:\n",
+ " tau_slider.value = tau\n",
+ " if kappa:\n",
+ " kappa_slider.value = kappa\n",
+ " if omega:\n",
+ " omega_slider.value = omega\n",
+ "\n",
+ "def update_and_render(nu=None, tau=None, kappa=None, omega=None):\n",
+ " update(nu, tau, kappa, omega)\n",
+ " render()\n",
+ "\n",
+ "\n",
+ "default_button = widgets.Button(description=\"Default\")\n",
+ "def default_fun(b):\n",
+ " reset(nu=default_nu, tau=default_tau, kappa=default_kappa, omega=default_omega)\n",
+ "default_button.on_click(default_fun)\n",
+ "\n",
+ "otsu_button = widgets.Button(description=\"Otsu's Method\")\n",
+ "def otsu_fun(b):\n",
+ " reset(nu=1e30, tau=1e-30, kappa=1e-30)\n",
+ "otsu_button.on_click(otsu_fun)\n",
+ "\n",
+ "met_button = widgets.Button(description=\"MET\")\n",
+ "def met_fun(b):\n",
+ " reset(nu=1e-30, kappa=1e-30,)\n",
+ "met_button.on_click(met_fun)\n",
+ "\n",
+ "percentile_button = widgets.Button(description=\"Percentile\")\n",
+ "def percentile_fun(b):\n",
+ " reset(nu=1e-30, kappa=1e30)\n",
+ "percentile_button.on_click(percentile_fun)\n",
+ "\n",
+ "display(default_button)\n",
+ "display(widgets.HBox([otsu_button, met_button, percentile_button]), widgets.Output())\n",
+ "\n",
+ "widgets.interact(update_and_render,\n",
+ " nu=nu_slider,\n",
+ " tau=tau_slider,\n",
+ " kappa=kappa_slider,\n",
+ " omega=omega_slider);\n"
+ ],
+ "execution_count": null,
+ "outputs": []
}
- ],
- "source": [
- "#@title An interactive viewer for tuning hyperparameters\n",
- "\n",
- "# Load the image\n",
- "from PIL import Image\n",
- "import io\n",
- "import numpy as np\n",
- "\n",
- "image_data = list(uploader.value.values())[0]['content']\n",
- "im = np.array(Image.open(io.BytesIO(image_data)))\n",
- "\n",
- "# A fast numpy reference implementation of GHT, as per\n",
- "# \"A Generalization of Otsu's Method and Minimum Error Thresholding\"\n",
- "# Jonathan T. Barron, ECCV, 2020\n",
- "\n",
- "csum = lambda z: np.cumsum(z)[:-1]\n",
- "dsum = lambda z: np.cumsum(z[::-1])[-2::-1]\n",
- "argmax = lambda x, f: np.mean(x[:-1][f == np.max(f)]) # Use the mean for ties.\n",
- "clip = lambda z: np.maximum(1e-30, z)\n",
- "\n",
- "def preliminaries(n, x):\n",
- " \"\"\"Some math that is shared across multiple algorithms.\"\"\"\n",
- " assert np.all(n >= 0)\n",
- " x = np.arange(len(n), dtype=n.dtype) if x is None else x\n",
- " assert np.all(x[1:] >= x[:-1])\n",
- " w0 = clip(csum(n))\n",
- " w1 = clip(dsum(n))\n",
- " p0 = w0 / (w0 + w1)\n",
- " p1 = w1 / (w0 + w1)\n",
- " mu0 = csum(n * x) / w0\n",
- " mu1 = dsum(n * x) / w1\n",
- " d0 = csum(n * x**2) - w0 * mu0**2\n",
- " d1 = dsum(n * x**2) - w1 * mu1**2\n",
- " return x, w0, w1, p0, p1, mu0, mu1, d0, d1\n",
- "\n",
- "def GHT(n, x=None, nu=0, tau=0, kappa=0, omega=0.5, prelim=None):\n",
- " assert nu >= 0\n",
- " assert tau >= 0\n",
- " assert kappa >= 0\n",
- " assert omega >= 0 and omega <= 1\n",
- " x, w0, w1, p0, p1, _, _, d0, d1 = prelim or preliminaries(n, x)\n",
- " v0 = clip((p0 * nu * tau**2 + d0) / (p0 * nu + w0))\n",
- " v1 = clip((p1 * nu * tau**2 + d1) / (p1 * nu + w1))\n",
- " f0 = -d0 / v0 - w0 * np.log(v0) + 2 * (w0 + kappa * omega) * np.log(w0)\n",
- " f1 = -d1 / v1 - w1 * np.log(v1) + 2 * (w1 + kappa * (1 - omega)) * np.log(w1)\n",
- " return argmax(x, f0 + f1), f0 + f1\n",
- "\n",
- "def im2hist(im, zero_extents=False):\n",
- " # Convert an image to grayscale, bin it, and optionally zero out the first and last bins.\n",
- " max_val = np.iinfo(im.dtype).max\n",
- " x = np.arange(max_val+1)\n",
- " e = np.arange(-0.5, max_val+1.5)\n",
- " assert len(im.shape) in [2, 3]\n",
- " im_bw = np.amax(im[...,:3], -1) if len(im.shape) == 3 else im\n",
- " n = np.histogram(im_bw, e)[0]\n",
- " if zero_extents:\n",
- " n[0] = 0\n",
- " n[-1] = 0\n",
- " return n, x, im_bw\n",
- "\n",
- "# Precompute a histogram and some integrals.\n",
- "n, x, im_bw = im2hist(im, True)\n",
- "prelim = preliminaries(n, x)\n",
- "\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "default_nu = np.sum(n)\n",
- "default_tau = np.sqrt(1/12)\n",
- "default_kappa = np.sum(n)\n",
- "default_omega = 0.5\n",
- "\n",
- "_nu = default_nu\n",
- "_tau = default_tau\n",
- "_kappa = default_kappa\n",
- "_omega = default_omega\n",
- "\n",
- "continuous_update = True\n",
- "nu_slider = widgets.FloatLogSlider(min=-30, max=30, value=_nu, step=1., continuous_update=continuous_update)\n",
- "tau_slider = widgets.FloatLogSlider(min=-30, max=30, value=_tau, step=1., continuous_update=continuous_update)\n",
- "kappa_slider = widgets.FloatLogSlider(min=-30, max=30, value=_kappa, step=1., continuous_update=continuous_update)\n",
- "omega_slider = widgets.FloatSlider(min=0, max=1, value=_omega, step=0.01, continuous_update=continuous_update)\n",
- "\n",
- "def render():\n",
- " global _nu, _tau, _kappa, _omega\n",
- " t, score = GHT(n, x, _nu, _tau, _kappa, _omega, prelim)\n",
- "\n",
- " plt.figure(0, figsize=(16,5))\n",
- " plt.subplot(1,3,1)\n",
- " plt.imshow(im, cmap='gray')\n",
- " plt.axis('off')\n",
- "\n",
- " plt.subplot(1,3,2)\n",
- " plt.imshow(im_bw > t, cmap='gray', vmin=0, vmax=1)\n",
- " plt.gca().set_xticks([])\n",
- " plt.gca().set_yticks([])\n",
- "\n",
- " plt.subplot(1,3,3)\n",
- " normalize = lambda x : (x - np.min(score)) * np.max(n) / (np.max(score) - np.min(score))\n",
- " plt.plot((x[:-1] + x[1:])/2, normalize(score))\n",
- " plt.scatter(t, normalize(score[int(t)]))\n",
- " plt.bar(x, n, width=1)\n",
- " plt.gca().set_yticks([]);\n",
- "\n",
- "def update(nu=None, tau=None, kappa=None, omega=None):\n",
- " global _nu, _tau, _kappa, _omega\n",
- " _nu = nu or _nu\n",
- " _tau = tau or _tau\n",
- " _kappa = kappa or _kappa\n",
- " _omega = omega or _omega\n",
- "\n",
- "def reset(nu=None, tau=None, kappa=None, omega=None):\n",
- " global nu_slider, tau_slider, kappa_slider, omega_slider\n",
- " if nu:\n",
- " nu_slider.value = nu\n",
- " if tau:\n",
- " tau_slider.value = tau\n",
- " if kappa:\n",
- " kappa_slider.value = kappa\n",
- " if omega:\n",
- " omega_slider.value = omega\n",
- "\n",
- "def update_and_render(nu=None, tau=None, kappa=None, omega=None):\n",
- " update(nu, tau, kappa, omega)\n",
- " render()\n",
- "\n",
- "\n",
- "default_button = widgets.Button(description=\"Default\")\n",
- "def default_fun(b):\n",
- " reset(nu=default_nu, tau=default_tau, kappa=default_kappa, omega=default_omega)\n",
- "default_button.on_click(default_fun)\n",
- "\n",
- "otsu_button = widgets.Button(description=\"Otsu's Method\")\n",
- "def otsu_fun(b):\n",
- " reset(nu=1e30, tau=1e-30, kappa=1e-30)\n",
- "otsu_button.on_click(otsu_fun)\n",
- "\n",
- "met_button = widgets.Button(description=\"MET\")\n",
- "def met_fun(b):\n",
- " reset(nu=1e-30, kappa=1e-30,)\n",
- "met_button.on_click(met_fun)\n",
- "\n",
- "percentile_button = widgets.Button(description=\"Percentile\")\n",
- "def percentile_fun(b):\n",
- " reset(nu=1e-30, kappa=1e30)\n",
- "percentile_button.on_click(percentile_fun)\n",
- "\n",
- "display(default_button)\n",
- "display(widgets.HBox([otsu_button, met_button, percentile_button]), widgets.Output())\n",
- "\n",
- "widgets.interact(update_and_render,\n",
- " nu=nu_slider,\n",
- " tau=tau_slider,\n",
- " kappa=kappa_slider,\n",
- " omega=omega_slider);\n"
- ]
- }
- ],
- "metadata": {
- "colab": {
- "collapsed_sections": [],
- "include_colab_link": true,
- "name": "interactive_viewer.ipynb",
- "provenance": []
- },
- "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.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
+ ]
+}
\ No newline at end of file