Add draw_uv.ipynb for UV layout generation, including image processing and canvas creation. Updated find_cute_box_with_image.ipynb with new functions for 3D coordinate extraction and improved type annotations.

This commit is contained in:
2025-04-24 12:56:34 +08:00
parent 9e1ac3d941
commit 801485e6d5
2 changed files with 101 additions and 12 deletions

View File

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 33, "execution_count": 77,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -29,7 +29,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 34, "execution_count": 78,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -42,7 +42,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 35, "execution_count": 79,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -54,7 +54,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 36, "execution_count": 80,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -66,7 +66,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 37, "execution_count": 81,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -88,7 +88,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 38, "execution_count": 82,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -121,7 +121,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 83,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -192,7 +192,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 43, "execution_count": 86,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -286,7 +286,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 46, "execution_count": null,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -295,9 +295,98 @@
" uv_points = marker.corners\n", " uv_points = marker.corners\n",
" return interpolate_uvs_to_3d_trimesh(uv_points, mesh)\n", " return interpolate_uvs_to_3d_trimesh(uv_points, mesh)\n",
"\n", "\n",
"results = [marker_to_3d_coords(marker, m) for marker in output_markers]\n", "id_to_3d_coords = {marker.id: 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\n",
"# note that the glb is Y up (but in blender it's Z up)" "# 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()"
] ]
} }
], ],