{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Polarizer optimization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "\n", "An interesting feature of Mitsuba is its ability to account for the polarization state of light. This becomes even more powerful when combined with differentiable rendering. \n", "\n", "This tutorial demonstrates how those two concepts can be used together to perform a simple optimization. The setup is the following: we place two linear polarization filters in front of the camera. Initially, these are rotated in such a way that all the light passes through them. The optimization process will attempt to rotate one of the filter to minimize the overall brightness of the rendered image. Indeed, it is known that rotating this filter by 90 degrees will lead to complete cancelation of the polarization state, resulting in a darker image.\n", "\n", "More information about polarization can be found [here][1].\n", "\n", "
\n", "\n", "🚀 **You will learn how to:**\n", " \n", "\n", " \n", "
\n", "\n", "[1]: https://mitsuba.readthedocs.io/en/latest/src/key_topics/polarization.html" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## Reference image\n", "\n", "As usual, let's import the necessary libraries. For the sake of this tutorial, we already provide an XML file for the scene containing both linear polarization filter (e.g. using the [polarizer][1] BSDF).\n", "\n", "[1]: https://mitsuba.readthedocs.io/en/latest/src/generated/plugins_bsdfs.html#linear-polarizer-material-polarizer" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2021-09-17T09:13:32.691239Z", "start_time": "2021-09-17T09:13:32.226341Z" } }, "outputs": [], "source": [ "import drjit as dr \n", "import mitsuba as mi\n", "\n", "mi.set_variant('llvm_ad_rgb_polarized')\n", "\n", "scene = mi.load_file('../scenes/polarizers.xml')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can then perform the rendering of our initial scene. As expected, the two filters are aligned and let linearly polarized light through." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2021-09-17T09:13:33.024683Z", "start_time": "2021-09-17T09:13:32.803338Z" } }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Bitmap[\n", " pixel_format = rgb,\n", " component_format = uint8,\n", " size = [128, 128],\n", " srgb_gamma = 1,\n", " struct = Struct<3>[\n", " uint8 R; // @0, normalized, gamma, premultiplied alpha\n", " uint8 G; // @1, normalized, gamma, premultiplied alpha\n", " uint8 B; // @2, normalized, gamma, premultiplied alpha\n", " ],\n", " data = [ 48 KiB of image data ]\n", "]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image_init = mi.render(scene, spp=8)\n", "\n", "mi.util.convert_to_bitmap(image_init)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup optimization\n", "\n", "As in the previous tutorial on [pose estimation][1], we setup the optimization using a latent variable to control the rotation of the filter. This rotation angle will be used to construct a transformation matrix that will be applied to all vertices of the filter's mesh. For convenience, we define a function that does all of this, which we will also call later during the optimization loop.\n", "\n", "It is important to apply the rotation once before starting the optimization loop as this will *bind* the optimizer variable to the scene parameter. Otherwise during backpropagation the gradients wouldn't be propagate all the way to the optimizer's variable.\n", "\n", "[1]: https://mitsuba.readthedocs.io/en/latest/src/inverse_rendering/reparam_optimization.html" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2021-09-17T09:13:33.092925Z", "start_time": "2021-09-17T09:13:33.086230Z" } }, "outputs": [], "source": [ "params = mi.traverse(scene)\n", "\n", "# Key of the scene parameter to be optimized\n", "key = 'filter2.vertex_positions'\n", "\n", "# Get the initial vertex positions\n", "v_positions_init = dr.unravel(mi.Vector3f, params[key])\n", "\n", "# Instantiate an Adam optimizer and define a latent variable `rotation`\n", "opt = mi.ad.Adam(lr=1.0)\n", "opt['rotation'] = mi.Float(0.0)\n", "\n", "# Apply optimized rotation value to mesh vertices\n", "def apply_rotation():\n", " transform = mi.Transform4f.rotate([0, 0, 1], opt['rotation'])\n", " positions_new = transform @ v_positions_init\n", " params[key] = dr.ravel(positions_new)\n", " params.update()\n", "\n", "# Perform the first rotation to enable derivative tracking on the scene parameters\n", "apply_rotation()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Optimization\n", "\n", "Everything is now ready to run the optimization loop. \n", "\n", "In the following cell we define the hyper parameters controlling our optimization loop, such as the number of iterations:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "iteration_count = 100" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "nbsphinx": "hidden", "tags": [] }, "outputs": [], "source": [ "# IGNORE THIS: When running under pytest, adjust parameters to reduce computation time\n", "import os\n", "if 'PYTEST_CURRENT_TEST' in os.environ:\n", " iteration_count = 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this example the loss function doesn't compare against a reference as the goal is simply to make the image darker. For this we simply use the sum of the pixel values in the rendered image." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2021-09-17T09:13:58.916031Z", "start_time": "2021-09-17T09:13:33.094709Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Iteration: 99, rot: 90.0260, loss: 0.0817\n", "Optimization complete!\n" ] } ], "source": [ "angles = []\n", "losses = []\n", "\n", "for it in range(iteration_count):\n", " # Perform the differentiable rendering simulation\n", " image = mi.render(scene, params=params, seed=it, spp=1)\n", "\n", " # Objective: no comparison against a reference, the goal is simply to make the image darker\n", " ob_val = dr.mean(image)\n", "\n", " # Backpropagate loss to input parameters\n", " dr.backward(ob_val)\n", "\n", " # Optimizer: take a gradient step\n", " opt.step()\n", "\n", " # Apply rotation and update the scene parameters\n", " apply_rotation()\n", " \n", " print(f\"Iteration: {it:2}, rot: {opt['rotation'][0]:.4f}, loss: {ob_val[0]:.4f}\", end='\\r')\n", " angles.append(opt['rotation'][0])\n", " losses.append(ob_val[0])\n", "\n", "print() \n", "print('Optimization complete!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Results\n", "\n", "We can now look at the optimized scene, which appears much darker as expected." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Bitmap[\n", " pixel_format = rgb,\n", " component_format = uint8,\n", " size = [128, 128],\n", " srgb_gamma = 1,\n", " struct = Struct<3>[\n", " uint8 R; // @0, normalized, gamma, premultiplied alpha\n", " uint8 G; // @1, normalized, gamma, premultiplied alpha\n", " uint8 B; // @2, normalized, gamma, premultiplied alpha\n", " ],\n", " data = [ 48 KiB of image data ]\n", "]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image_final = mi.render(scene, seed=0, spp=8)\n", "\n", "mi.util.convert_to_bitmap(image_final)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We plot the filter rotation and image loss accross the optimization loop." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "nbsphinx-thumbnail": {}, "tags": [] }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "from matplotlib import pyplot as plt\n", "\n", "fig, ax = plt.subplots(ncols=2, figsize=(12,4))\n", "\n", "ax[0].plot(angles);\n", "ax[0].set_ylabel('angle'); \n", "ax[0].set_title('Filter rotation');\n", "ax[0].set_xlim([0, 99]); \n", "ax[0].set_ylim([0, 100])\n", "\n", "ax[1].plot(losses); \n", "ax[1].set_title('Image loss')\n", "ax[1].set_xlim([0, 99]); \n", "ax[1].set_ylim([0.08, 0.11])\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## See also\n", "\n", "- [polarizer plugin](https://mitsuba.readthedocs.io/en/latest/src/generated/plugins_bsdfs.html#linear-polarizer-material-polarizer)" ] } ], "metadata": { "file_extension": ".py", "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" }, "metadata": { "interpreter": { "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" } }, "mimetype": "text/x-python", "name": "python", "npconvert_exporter": "python", "pygments_lexer": "ipython3", "version": 3 }, "nbformat": 4, "nbformat_minor": 4 }