From 5612184ff5abaa647fe572d0aa739a1f3d0427f7 Mon Sep 17 00:00:00 2001 From: "artur.trzesiok@gmail.com" Date: Thu, 4 Jan 2024 16:59:03 +0100 Subject: [PATCH] Is there a way to include mutliple colour arrays for Points (or any other) drawables? #436 --- ...t_cloud_advanced_compression_in_html.ipynb | 304 ++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 examples/point_cloud_advanced_compression_in_html.ipynb diff --git a/examples/point_cloud_advanced_compression_in_html.ipynb b/examples/point_cloud_advanced_compression_in_html.ipynb new file mode 100644 index 00000000..0b25b359 --- /dev/null +++ b/examples/point_cloud_advanced_compression_in_html.ipynb @@ -0,0 +1,304 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from k3d.helpers import download\n", + "from pyunpack import Archive\n", + "import os\n", + "from IPython.display import IFrame\n", + "\n", + "filename = download('http://www.semantic3d.net/data/point-clouds/testing1/stgallencathedral_station1_intensity_rgb.7z')\n", + "Archive(filename).extractall('./')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import numpy as np \n", + "\n", + "data = None\n", + "\n", + "with open(filename.replace('.7z', '.txt'), mode='r') as csv_file:\n", + " csv_reader = csv.reader(csv_file, delimiter=' ') \n", + " data = np.array(list(csv_reader), dtype=np.float32)\n", + "\n", + "# compute color in hex format\n", + "data[:, 4] = np.sum(data[:, 4:7].astype(np.uint32) * np.array([1, 256, 256 ** 2]), axis=1) \n", + "data = data[:, 0:5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "positions = data[::10, 0:3]\n", + "colors1 = data[::10, 4].astype(np.uint32)\n", + "colors2 = np.clip(colors1.view(np.uint8) * 1.5, 0, 255).astype(np.uint8).view('uint32')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "positions.shape, colors1.shape, colors2.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "cam_pos = [5.251483149143791,\n", + " -7.92683507646606,\n", + " 3.144285796928443,\n", + " -2.470283607444292,\n", + " 3.6558150584160503,\n", + " 2.3721091212696286,\n", + " 0,\n", + " 0,\n", + " 1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import json\n", + "import k3d\n", + "import ipywidgets as widgets\n", + "\n", + "plot = k3d.plot()\n", + "plot += k3d.points(positions, colors1, point_size=0.2, shader=\"flat\") \n", + "plot += k3d.points(positions, colors2, point_size=0.2, shader=\"flat\") \n", + "plot.display()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot.camera = cam_pos" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"point_cloud_full.html\", \"w\") as f:\n", + " f.write(plot.get_snapshot(additional_js_code=\"\"\"\n", + " let json = K3DInstance.getWorld().ObjectsListJson; \n", + " let active = Object.keys(json)[0];\n", + " \n", + " setInterval(() => {\n", + " let newActive;\n", + " \n", + " Object.keys(json).forEach(function (id) {\n", + " if (active === id) {\n", + " json[id].opacity = 0;\n", + " K3DInstance.reload(json[id], {opacity: 0}); \n", + " } else {\n", + " json[id].opacity = 1;\n", + " K3DInstance.reload(json[id], {opacity: 1});\n", + " newActive = id;\n", + " } \n", + " });\n", + " \n", + " active = newActive;\n", + " \n", + " }, 2000);\n", + " \n", + " \n", + " \"\"\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# size in html\n", + "os.stat(\"point_cloud_full.html\").st_size / 1024 / 1024 # size in MB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "IFrame('point_cloud_full.html', width=900, height=350)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Advanced approach" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import json\n", + "import k3d\n", + "import ipywidgets as widgets\n", + "\n", + "plot2 = k3d.plot()\n", + "\n", + "positions_placeholder = positions.copy()\n", + "positions_placeholder.fill(0.0) # filling with one value will boost compression ratio\n", + "\n", + "plot2 += k3d.points(positions, colors1, point_size=0.2, shader=\"flat\", name=\"main\") \n", + "plot2 += k3d.points(positions_placeholder, colors2, point_size=0.2, shader=\"flat\", name=\"second\") \n", + "\n", + "plot2.display()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot2.camera = cam_pos" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"point_cloud_advanced.html\", \"w\") as f:\n", + " f.write(plot2.get_snapshot(additional_js_code=\"\"\"\n", + " let json = K3DInstance.getWorld().ObjectsListJson; \n", + " let active = Object.keys(json)[0];\n", + " let positions = null;\n", + " \n", + " // search for main and save positions from it\n", + " Object.keys(json).forEach(function (id) {\n", + " if (json[id].name === 'main') {\n", + " positions = json[id].positions.data;\n", + " }\n", + " });\n", + " \n", + " // search for second and update positions\n", + " Object.keys(json).forEach(function (id) {\n", + " if (json[id].name === 'second') {\n", + " json[id].positions.data.set(positions);\n", + " K3DInstance.reload(json[id], {positions: json[id].positions}); \n", + " }\n", + " });\n", + " \n", + " \n", + " // like before\n", + " \n", + " setInterval(() => {\n", + " let json = K3DInstance.getWorld().ObjectsListJson;\n", + " let newActive;\n", + " \n", + " Object.keys(json).forEach(function (id) {\n", + " if (active === id) {\n", + " json[id].opacity = 0;\n", + " K3DInstance.reload(json[id], {opacity: 0}); \n", + " } else {\n", + " json[id].opacity = 1;\n", + " K3DInstance.reload(json[id], {opacity: 1});\n", + " newActive = id;\n", + " } \n", + " });\n", + " \n", + " active = newActive;\n", + " \n", + " }, 2000);\n", + " \n", + " \n", + " \"\"\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# size in html\n", + "os.stat(\"point_cloud_advanced.html\").st_size / 1024 / 1024 # size in MB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "IFrame('point_cloud_advanced.html', width=900, height=350)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ratio\n", + "os.stat(\"point_cloud_advanced.html\").st_size / os.stat(\"point_cloud_full.html\").st_size" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ratio cannot be 0.5 because we pass information about each points color" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}