diff --git a/draw.ipynb b/draw_uv.ipynb similarity index 100% rename from draw.ipynb rename to draw_uv.ipynb diff --git a/find_cute_box_with_image.ipynb b/find_cute_box_with_image.ipynb index 67a4385..6f4317c 100644 --- a/find_cute_box_with_image.ipynb +++ b/find_cute_box_with_image.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 33, + "execution_count": 77, "metadata": {}, "outputs": [], "source": [ @@ -29,7 +29,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 78, "metadata": {}, "outputs": [], "source": [ @@ -42,7 +42,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 79, "metadata": {}, "outputs": [], "source": [ @@ -54,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 80, "metadata": {}, "outputs": [], "source": [ @@ -66,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 81, "metadata": {}, "outputs": [], "source": [ @@ -88,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 82, "metadata": {}, "outputs": [], "source": [ @@ -121,7 +121,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 83, "metadata": {}, "outputs": [], "source": [ @@ -192,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 86, "metadata": {}, "outputs": [], "source": [ @@ -286,7 +286,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -295,9 +295,98 @@ " uv_points = marker.corners\n", " return interpolate_uvs_to_3d_trimesh(uv_points, mesh)\n", "\n", - "results = [marker_to_3d_coords(marker, m) for marker in output_markers]\n", - "id_to_3d_coords = {marker.id: result for marker, result in zip(output_markers, results)}\n", - "# note that the glb is Y up (but in blender it's Z up)" + "id_to_3d_coords = {marker.id: marker_to_3d_coords(marker, m) for marker in output_markers}\n", + "# note that the glb is Y up\n", + "# when visualizing with matplotlib, it's Z up\n", + "# GLTF → Blender: (X, Y, Z) → (X, -Z, Y)\n", + "OPEN_GL_TO_BLENDER = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]])\n", + "# Blender → GLTF: (X, Y, Z) → (X, Z, -Y)\n", + "BLENDER_TO_OPEN_GL = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])\n", + "display(np.linalg.inv(OPEN_GL_TO_BLENDER)) # should be the same" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [], + "source": [ + "# matplotlib default colors scheme\n", + "colors: list[str] = plt.rcParams[\"axes.prop_cycle\"].by_key()[\"color\"]\n", + "\n", + "def hex_to_rgb(hex_color: str) -> tuple[float, float, float]:\n", + " assert hex_color.startswith(\"#\")\n", + " assert len(hex_color) == 7\n", + " return tuple(int(hex_color[i:i+2], 16) / 255.0 for i in (1, 3, 5)) # type: ignore" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from functools import lru_cache\n", + "\n", + "@dataclass\n", + "class Face:\n", + " color: tuple[float, float, float]\n", + " marker_ids: list[int]\n", + "\n", + "\n", + "# fmt: off\n", + "layout:list[list[Optional[int]]] = [\n", + " [None, None, 0, None, None],\n", + " [None, None, 1, None, None],\n", + " [None, 5, 2, 4, None],\n", + " [None, None, 3, None, None],\n", + "]\n", + "# fmt: on\n", + "\n", + "faces = {\n", + " \"bottom\": Face(color=hex_to_rgb(colors[0]), marker_ids=[0, 1, 2, 3]),\n", + " \"back\": Face(color=hex_to_rgb(colors[1]), marker_ids=[4, 5, 6, 7]),\n", + " \"top\": Face(color=hex_to_rgb(colors[2]), marker_ids=[8, 9, 10, 11]),\n", + " \"front\": Face(color=hex_to_rgb(colors[3]), marker_ids=[12, 13, 14, 15]),\n", + " \"right\": Face(color=hex_to_rgb(colors[4]), marker_ids=[16, 17, 18, 19]),\n", + " \"left\": Face(color=hex_to_rgb(colors[5]), marker_ids=[20, 21, 22, 23]),\n", + "}\n", + "\n", + "@lru_cache\n", + "def get_face_by_marker_id(marker_id: int) -> Optional[Face]:\n", + " for face in faces.values():\n", + " if marker_id in face.marker_ids:\n", + " return face\n", + " return None\n", + "\n", + "\n", + "# 3D Visualization (with flipped and fully valid data)\n", + "fig = plt.figure(figsize=(8, 8))\n", + "ax = fig.add_subplot(111, projection=\"3d\")\n", + "\n", + "for tag_id, corners in id_to_3d_coords.items():\n", + " corners = np.array(corners)\n", + " face = get_face_by_marker_id(tag_id)\n", + " assert face is not None\n", + " color = face.color\n", + " for i in range(4):\n", + " p1 = corners[i]\n", + " p2 = corners[(i + 1) % 4]\n", + " ax.plot(*zip(p1, p2), color=color)\n", + " center = corners.mean(axis=0)\n", + " ax.scatter(*center, color=color)\n", + " ax.text(*center, str(tag_id), fontsize=9, color=\"black\") # type: ignore\n", + "\n", + "ax.set_box_aspect([1, 1, 1]) # type: ignore\n", + "ax.set_title(\"ArUco Corners in 3D\")\n", + "ax.set_xlabel(\"X\")\n", + "ax.set_ylabel(\"Y\")\n", + "ax.set_zlabel(\"Z\") # type: ignore\n", + "\n", + "# Set the viewing angle\n", + "# ax.view_init(elev=60, azim=35) # type: ignore\n", + "\n", + "plt.show()" ] } ],