{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Proto-object in motion\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import pandas as pd\nimport torch\n\nimport matplotlib.pyplot as plt\nfrom matplotlib import animation\nfrom IPython.display import HTML\n\nfrom deadleaves import (\n LeafGeometryGenerator,\n LeafAppearanceSampler,\n ImageRenderer,\n LeafTopology,\n)\n\n\nimage_shape = (512, 731)\narea = image_shape[0] * image_shape[1]\n\nshared_params = {\n \"leaf_shape\": \"circular\",\n \"shape_param_distributions\": {\n \"area\": {\"uniform\": {\"low\": area * 0.005, \"high\": area * 0.01}}\n },\n \"image_shape\": image_shape,\n}\n\ntable_background, _ = LeafGeometryGenerator(\n **shared_params,\n n_sample=200,\n).generate_segmentation()\n\ntable_target, _ = LeafGeometryGenerator(\n **shared_params,\n n_sample=10,\n position_mask={\"shape\": \"circular\", \"params\": {\"area\": area * 0.05}},\n).generate_segmentation()\n\ntable_background = LeafAppearanceSampler(leaf_table=table_background).sample_color(\n color_param_distributions={\"gray\": {\"normal\": {\"loc\": 0.5, \"scale\": 0.2}}},\n)\n\ntable_target = LeafAppearanceSampler(leaf_table=table_target).sample_color(\n color_param_distributions={\n \"R\": {\"uniform\": {\"low\": 0.2, \"high\": 1.0}},\n \"G\": {\"constant\": {\"value\": 0.0}},\n \"B\": {\"constant\": {\"value\": 0.0}},\n },\n)\n\ntable_background[\"type\"] = \"background\"\ntable_target[\"type\"] = \"target\"\n\ntopology = LeafTopology(image_shape=image_shape)\n\ntable_merged = topology.merge_leaf_tables(table_background, table_target)\ntable_merged = LeafTopology.randomize_index(table_merged, seed=42)\n\n\ndef move_leaves_one_step(\n leaf_table: pd.DataFrame,\n frame_idx: int,\n image_shape: tuple[int, int],\n radius: float = 5.0,\n target_velocity: tuple[float, float] = (1.0, 0.0),\n bg_angles: torch.Tensor | None = None,\n bg_angular_velocities: torch.Tensor | None = None,\n) -> pd.DataFrame:\n table = leaf_table.copy()\n\n # Identify background and target leaves\n bg_mask = table[\"type\"] != \"target\"\n target_mask = table[\"type\"] == \"target\"\n\n n_bg = bg_mask.sum()\n bg_indices = table.index[bg_mask]\n\n # Initialize angles and angular velocities if not provided\n if bg_angles is None:\n bg_angles = torch.distributions.uniform.Uniform(0, 2 * torch.pi).sample((n_bg,))\n if bg_angular_velocities is None:\n bg_angular_velocities = torch.distributions.uniform.Uniform(0.02, 0.05).sample(\n (n_bg,)\n )\n\n # Move background leaves\n for i, idx in enumerate(bg_indices):\n angle = bg_angles[i] + frame_idx * bg_angular_velocities[i]\n dx = radius * torch.cos(angle)\n dy = radius * torch.sin(angle)\n table.loc[idx, \"x_pos\"] = table.loc[idx, \"x_pos\"] + dx\n table.loc[idx, \"y_pos\"] = table.loc[idx, \"y_pos\"] + dy\n\n # Move target leaves linearly\n table.loc[target_mask, \"x_pos\"] = (\n leaf_table.loc[target_mask, \"x_pos\"] + frame_idx * target_velocity[0]\n ) % image_shape[1]\n table.loc[target_mask, \"y_pos\"] = (\n leaf_table.loc[target_mask, \"y_pos\"] + frame_idx * target_velocity[1]\n ) % image_shape[0]\n return table\n\n\nframes = []\nn_frames = 10\nfor t in range(n_frames):\n table = move_leaves_one_step(\n leaf_table=table_merged,\n image_shape=image_shape,\n frame_idx=t,\n radius=5.0,\n target_velocity=(image_shape[1] / n_frames, 0.0),\n )\n\n renderer = ImageRenderer(\n leaf_table=table,\n image_shape=image_shape,\n background_color=torch.tensor(1.0),\n )\n image = renderer.render_image()\n frames.append(image.cpu())\n\nfig, ax = plt.subplots(figsize=(7.31, 5.12))\nim = ax.imshow(frames[0])\nax.axis(\"off\")\nax.set_position((0.0, 0.0, 1.0, 1.0))\n\n\ndef update(i):\n im.set_data(frames[i])\n return [im]\n\n\nani = animation.FuncAnimation(\n fig,\n update,\n frames=n_frames,\n interval=100,\n blit=True,\n)\n\nplt.close(fig)\nHTML(ani.to_jshtml())" ] } ], "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.12.3" } }, "nbformat": 4, "nbformat_minor": 0 }