Created
March 31, 2020 18:32
-
-
Save deeplook/d9ac96508362ce5eb5015a7e449eb0b6 to your computer and use it in GitHub Desktop.
Explore seam on textures mapped to spheres
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Explore texture seam on spheres" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import numpy as np\n", | |
"import ipyvolume as ipv\n", | |
"from PIL import Image\n", | |
"from ipywidgets import interact" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Define sphere" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2020-03-28T12:43:46.345724Z", | |
"start_time": "2020-03-28T12:43:46.337716Z" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"def sphere(x, y, z, radius, color=\"red\", texture=None, num=100):\n", | |
" \"\"\"Create a sphere mesh with origin at x, y, z and radius.\n", | |
" \"\"\"\n", | |
" assert num > 0\n", | |
" \n", | |
" # First compute the unit vectors and scale them:\n", | |
" phi = np.linspace(0, 2 * np.pi, num)\n", | |
" theta = np.linspace(0, np.pi, num)\n", | |
" xu = np.outer(np.cos(phi), np.sin(theta))\n", | |
" yu = np.outer(np.sin(phi), np.sin(theta))\n", | |
" zu = np.outer(np.ones(np.size(phi)), np.cos(theta))\n", | |
" X = x + radius * xu\n", | |
" Y = y + radius * yu\n", | |
" Z = z + radius * zu\n", | |
" \n", | |
" # Compute the lon and lat for a z-aligned sphere to change axis,\n", | |
" # the math changes but is essentially the same.\n", | |
" lon = np.arctan2(yu, xu)\n", | |
" lat = np.arcsin(zu)\n", | |
" \n", | |
" # Get U, V and move them to proper values:\n", | |
" u = 0.5 + lon / (2 * np.pi)\n", | |
" v = 0.5 + lat / np.pi\n", | |
"\n", | |
" return ipv.plot_mesh(X, Y, Z, u=u, v=v, color=color, texture=texture, wireframe=False)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "cddeef0a52ac4e7c8cc0695c59a7d96b", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"VBox(children=(Figure(camera=PerspectiveCamera(fov=46.0, position=(0.0, 0.0, 2.0), quaternion=(0.0, 0.0, 0.0, …" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"fig = ipv.figure()\n", | |
"s = sphere(0, 0, 0, radius=1, color=\"blue\", num=15)\n", | |
"ipv.show()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"s.color = \"red\"" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Generate textures" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def flat_image(width, height):\n", | |
" data = 100 * np.ones((height, width)).astype(np.uint8)\n", | |
" return Image.fromarray(data, \"L\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAIAAAABACAAAAAD3vSCjAAAAPklEQVR4nO3OMQEAAAjDsIFW/GtAxp7UQDOXblv+AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQByggA5F96DpsAAAAASUVORK5CYII=\n", | |
"text/plain": [ | |
"<PIL.Image.Image image mode=L size=128x64 at 0x121628750>" | |
] | |
}, | |
"execution_count": 6, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"flat_image(128, 64)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def random_image(width, height):\n", | |
" data = 255 * np.random.randint(0, 2, (height, width)).astype(np.uint8)\n", | |
" return Image.fromarray(data, \"L\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<PIL.Image.Image image mode=L size=128x64 at 0x1216A5790>" | |
] | |
}, | |
"execution_count": 8, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"random_image(128, 64)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def stripe_image(width, height):\n", | |
" a0 = np.zeros(height)\n", | |
" a1 = np.ones(height)\n", | |
" data = 255 * np.array([[a0, a1][i % 2] for i in range(width)]).T.astype(np.uint8)\n", | |
" return Image.fromarray(data, \"L\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAIAAAABACAAAAAD3vSCjAAAAPElEQVR4nO3OQREAAAzCMG7+PQ8ZfNIaSPLbL+MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkhAQD9DCv+KAAAAAElFTkSuQmCC\n", | |
"text/plain": [ | |
"<PIL.Image.Image image mode=L size=128x64 at 0x120A10490>" | |
] | |
}, | |
"execution_count": 10, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"stripe_image(128, 64)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Map textures on sphere" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2020-03-28T12:43:49.970693Z", | |
"start_time": "2020-03-28T12:43:46.702179Z" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "d154b56cd91f4a32b5757a05eaa62904", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"VBox(children=(Figure(camera=PerspectiveCamera(fov=46.0, position=(0.0, 0.0, 2.0), quaternion=(0.0, 0.0, 0.0, …" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"fig = ipv.figure()\n", | |
"s = sphere(0, 0, 0, radius=1, num=24)\n", | |
"ipv.show()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"s.texture = flat_image(16, 8)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "2421309defd844fcaceced428a0ee50b", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"VBox(children=(Figure(camera=PerspectiveCamera(fov=46.0, position=(0.0, 0.0, 2.0), quaternion=(0.0, 0.0, 0.0, …" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"fig = ipv.figure()\n", | |
"img = stripe_image(64, 4)\n", | |
"s = sphere(0, 0, 0, radius=1, num=24, texture=img)\n", | |
"ipv.show()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Add more interactivity" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "24908e4bb19346ccad27143dadd0b882", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"VBox(children=(Figure(camera=PerspectiveCamera(fov=46.0, position=(0.0, 0.0, 2.0), quaternion=(0.0, 0.0, 0.0, …" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"fig = ipv.figure()\n", | |
"s = sphere(0, 0, 0, radius=1, num=12)\n", | |
"ipv.show()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "5f027625f8e24e9c9e0a79981aa98f6c", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"interactive(children=(IntSlider(value=16, description='w', max=32, min=1), IntSlider(value=8, description='h',…" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"tx = None\n", | |
"\n", | |
"@interact\n", | |
"def retexture(w=(1, 32), h=(1, 16), typ=[\"stripe\", \"random\"]):\n", | |
" global tx\n", | |
" tx = stripe_image(w, h) if typ==\"stripe\" else random_image(w, h)\n", | |
" s.texture = tx\n", | |
" tx_norm = tx.resize((256, 128), Image.AFFINE)\n", | |
" return tx_norm" | |
] | |
} | |
], | |
"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.7.6" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment