From 309a25ac6a52d3952e06a88aa3d33f466892fee6 Mon Sep 17 00:00:00 2001 From: Yixing Lao Date: Sat, 28 Dec 2024 11:03:33 -0800 Subject: [PATCH] docs: introduce sphinx build, readthedocs, and docs workflow (#81) --- .github/workflows/docs.yml | 37 ++++++++ .gitignore | 2 + .readthedocs.yaml | 28 ++++++ README.md | 44 +++++++++- docs/Makefile | 20 +++++ docs/_static/.gitkeep | 0 docs/api.rst | 26 ++++++ docs/api/camera.rst | 9 ++ docs/api/colormap.rst | 9 ++ docs/api/convert.rst | 9 ++ docs/api/geometry.rst | 9 ++ docs/api/image.rst | 9 ++ docs/api/io.rst | 9 ++ docs/api/metric.rst | 9 ++ docs/api/normalize.rst | 9 ++ docs/api/project.rst | 9 ++ docs/api/raycast.rst | 9 ++ docs/api/render.rst | 9 ++ docs/api/solver.rst | 9 ++ docs/api/transform.rst | 9 ++ docs/camera.rst | 173 +++++++++++++++++++++++++++++++++++++ docs/conf.py | 103 ++++++++++++++++++++++ docs/contributing.rst | 40 +++++++++ docs/index.rst | 150 ++++++++++++++++++++++++++++++++ docs/installation.rst | 41 +++++++++ docs/make.bat | 35 ++++++++ pyproject.toml | 7 ++ 27 files changed, 819 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 .readthedocs.yaml create mode 100644 docs/Makefile create mode 100644 docs/_static/.gitkeep create mode 100644 docs/api.rst create mode 100644 docs/api/camera.rst create mode 100644 docs/api/colormap.rst create mode 100644 docs/api/convert.rst create mode 100644 docs/api/geometry.rst create mode 100644 docs/api/image.rst create mode 100644 docs/api/io.rst create mode 100644 docs/api/metric.rst create mode 100644 docs/api/normalize.rst create mode 100644 docs/api/project.rst create mode 100644 docs/api/raycast.rst create mode 100644 docs/api/render.rst create mode 100644 docs/api/solver.rst create mode 100644 docs/api/transform.rst create mode 100644 docs/camera.rst create mode 100644 docs/conf.py create mode 100644 docs/contributing.rst create mode 100644 docs/index.rst create mode 100644 docs/installation.rst create mode 100644 docs/make.bat diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..557aeb97 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,37 @@ +name: Docs + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + types: [opened, reopened, synchronize] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e .[docs] + + - name: Build documentation + run: | + cd docs + make clean && make html # SPHINXOPTS="-W --keep-going" + + - name: Notice + run: | + echo "Documentation build successful!" + echo "After merging this PR, you can view the latest documentation at:" + echo "- Public docs: https://camtools.readthedocs.io/en/latest/" + echo "- Admin panel: https://app.readthedocs.org/projects/camtools/" diff --git a/.gitignore b/.gitignore index cb172652..46f577c1 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,8 @@ instance/ # Sphinx documentation docs/_build/ +.doctrees +.buildinfo # PyBuilder target/ diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..dd3dc63f --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,28 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-24.04 + tools: + python: "3.10" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally declare the Python requirements required to build your docs +python: + install: + - method: pip + path: . + extra_requirements: + - docs + +# Optionally build your docs in additional formats such as PDF +formats: + - pdf diff --git a/README.md b/README.md index 7ce8cd37..92568783 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,20 @@ CamTools Logo

+

CamTools: Camera Tools for Computer Vision

+

+ Docs | + Repo | + Installation +

+ [![Formatter](https://github.com/yxlao/camtools/actions/workflows/formatter.yml/badge.svg)](https://github.com/yxlao/camtools/actions/workflows/formatter.yml) [![Unit Test](https://github.com/yxlao/camtools/actions/workflows/unit_test.yml/badge.svg)](https://github.com/yxlao/camtools/actions/workflows/unit_test.yml) [![PyPI](https://github.com/yxlao/camtools/actions/workflows/pypi.yml/badge.svg)](https://github.com/yxlao/camtools/actions/workflows/pypi.yml) -[![GitHub](https://img.shields.io/badge/GitHub-323940.svg?style=flat&logo=github&logoColor=959DA5)](https://github.com/yxlao/camtools) -[![Gitee](https://img.shields.io/badge/Gitee-323940.svg?style=flat&logo=gitee&logoColor=959DA5)](https://gitee.com/yxlao/camtools) [![PyPI](https://img.shields.io/pypi/v/camtools?style=flat&label=PyPI&logo=PyPI&logoColor=959DA5&labelColor=323940&color=808080)](https://pypi.org/project/camtools) +[![Docs](https://readthedocs.org/projects/camtools/badge/?version=latest)](https://camtools.readthedocs.io/en/latest/?badge=latest) CamTools is a collection of tools for handling cameras in computer vision. It can be used for plotting, converting, projecting, ray casting, and doing more @@ -20,8 +26,13 @@ clear and easy-to-use APIs.

- - CamTools Logo + + CamTools Logo

@@ -251,6 +262,31 @@ the beginning of the README. [part 2](https://ksimek.github.io/2012/08/22/extrinsic/), and [part 3](https://ksimek.github.io/2013/08/13/intrinsic/). +## Building Documentation + +To build and view the documentation locally: + +```bash +# Install documentation dependencies +pip install -e .[docs] + +# Build the documentation +make -C docs clean && make -C docs html + +# (Optional) Build the documentation with warnings as errors +make -C docs clean && make -C docs html SPHINXOPTS="-W --keep-going" + +# Start a local server to view the documentation +python -m http.server 8000 --directory docs/_build/html +``` + +Then open your browser and navigate to `http://localhost:8000` to view the documentation. + +The documentation is also automatically built by GitHub Actions on pull requests and pushes to main. After merging to main, you can view: + +- Public documentation at https://camtools.readthedocs.io/en/latest/ +- Admin panel at https://app.readthedocs.org/projects/camtools/ + ## Contributing - Follow [Angular's commit message convention](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#-commit-message-format) for PRs. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/.gitkeep b/docs/_static/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 00000000..b1cf0bdc --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,26 @@ +API Reference +============ + +.. toctree:: + :maxdepth: 1 + + api/camera + api/colormap + api/convert + api/geometry + api/image + api/io + api/metric + api/normalize + api/project + api/raycast + api/render + api/solver + api/transform + + +.. Not included in the docs website: +.. api/artifact +.. api/colmap +.. api/sanity +.. api/util diff --git a/docs/api/camera.rst b/docs/api/camera.rst new file mode 100644 index 00000000..e0d109ce --- /dev/null +++ b/docs/api/camera.rst @@ -0,0 +1,9 @@ +ct.camera +========= + +.. currentmodule:: ct + +.. automodule:: ct.camera + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/colormap.rst b/docs/api/colormap.rst new file mode 100644 index 00000000..ae2257e9 --- /dev/null +++ b/docs/api/colormap.rst @@ -0,0 +1,9 @@ +ct.colormap +=========== + +.. currentmodule:: ct + +.. automodule:: ct.colormap + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/convert.rst b/docs/api/convert.rst new file mode 100644 index 00000000..0959fc98 --- /dev/null +++ b/docs/api/convert.rst @@ -0,0 +1,9 @@ +ct.convert +========== + +.. currentmodule:: ct + +.. automodule:: ct.convert + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/geometry.rst b/docs/api/geometry.rst new file mode 100644 index 00000000..88b6d8aa --- /dev/null +++ b/docs/api/geometry.rst @@ -0,0 +1,9 @@ +ct.geometry +=========== + +.. currentmodule:: ct + +.. automodule:: ct.geometry + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/image.rst b/docs/api/image.rst new file mode 100644 index 00000000..3d4344b1 --- /dev/null +++ b/docs/api/image.rst @@ -0,0 +1,9 @@ +ct.image +======== + +.. currentmodule:: ct + +.. automodule:: ct.image + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/io.rst b/docs/api/io.rst new file mode 100644 index 00000000..c0e03d96 --- /dev/null +++ b/docs/api/io.rst @@ -0,0 +1,9 @@ +ct.io +======= + +.. currentmodule:: ct + +.. automodule:: ct.io + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/metric.rst b/docs/api/metric.rst new file mode 100644 index 00000000..69b32400 --- /dev/null +++ b/docs/api/metric.rst @@ -0,0 +1,9 @@ +ct.metric +========= + +.. currentmodule:: ct + +.. automodule:: ct.metric + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/normalize.rst b/docs/api/normalize.rst new file mode 100644 index 00000000..94df2fb1 --- /dev/null +++ b/docs/api/normalize.rst @@ -0,0 +1,9 @@ +ct.normalize +=========== + +.. currentmodule:: ct + +.. automodule:: ct.normalize + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/project.rst b/docs/api/project.rst new file mode 100644 index 00000000..7724b783 --- /dev/null +++ b/docs/api/project.rst @@ -0,0 +1,9 @@ +ct.project +========== + +.. currentmodule:: ct + +.. automodule:: ct.project + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/raycast.rst b/docs/api/raycast.rst new file mode 100644 index 00000000..90ae6365 --- /dev/null +++ b/docs/api/raycast.rst @@ -0,0 +1,9 @@ +ct.raycast +========== + +.. currentmodule:: ct + +.. automodule:: ct.raycast + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/render.rst b/docs/api/render.rst new file mode 100644 index 00000000..d715ad5a --- /dev/null +++ b/docs/api/render.rst @@ -0,0 +1,9 @@ +ct.render +========= + +.. currentmodule:: ct + +.. automodule:: ct.render + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/solver.rst b/docs/api/solver.rst new file mode 100644 index 00000000..a2b87679 --- /dev/null +++ b/docs/api/solver.rst @@ -0,0 +1,9 @@ +ct.solver +========= + +.. currentmodule:: ct + +.. automodule:: ct.solver + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/transform.rst b/docs/api/transform.rst new file mode 100644 index 00000000..89fca24e --- /dev/null +++ b/docs/api/transform.rst @@ -0,0 +1,9 @@ +ct.transform +=========== + +.. currentmodule:: ct + +.. automodule:: ct.transform + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/camera.rst b/docs/camera.rst new file mode 100644 index 00000000..5676b3a0 --- /dev/null +++ b/docs/camera.rst @@ -0,0 +1,173 @@ +Camera Coordinates +================== + +.. only:: not latex + + .. image:: https://raw.githubusercontent.com/yxlao/camtools/main/camtools/assets/camera_coordinates_light.png + :width: 520 + :align: center + :alt: Camera Coordinates + :class: only-light + + .. image:: https://raw.githubusercontent.com/yxlao/camtools/main/camtools/assets/camera_coordinates_dark.png + :width: 520 + :align: center + :alt: Camera Coordinates + :class: only-dark + +A homogeneous point ``[X, Y, Z, 1]`` in the world coordinate can be projected to a +homogeneous point ``[x, y, 1]`` in the image (pixel) coordinate using the +following equation: + +.. math:: + + \lambda + \left[\begin{array}{l} + x \\ + y \\ + 1 + \end{array}\right]=\left[\begin{array}{ccc} + f_{x} & 0 & c_{x} \\ + 0 & f_{y} & c_{y} \\ + 0 & 0 & 1 + \end{array}\right]\left[\begin{array}{llll} + R_{00} & R_{01} & R_{02} & t_{0} \\ + R_{10} & R_{11} & R_{12} & t_{1} \\ + R_{20} & R_{21} & R_{22} & t_{2} + \end{array}\right]\left[\begin{array}{c} + X \\ + Y \\ + Z \\ + 1 + \end{array}\right]. + +We follow the standard OpenCV-style camera coordinate system as illustrated at +the beginning of the documentation. + +Camera Coordinate +----------------- + +Right-handed, with :math:`Z` pointing away from the camera towards the view direction +and :math:`Y` axis pointing down. Note that the OpenCV convention (camtools' default) +is different from the OpenGL/Blender convention, where :math:`Z` points towards the +opposite view direction, :math:`Y` points up and :math:`X` points right. + +To convert between the OpenCV camera coordinates and the OpenGL-style coordinates, +use the conversion functions: + +- ``ct.convert.T_opencv_to_opengl()`` +- ``ct.convert.T_opengl_to_opencv()`` +- ``ct.convert.pose_opencv_to_opengl()`` +- ``ct.convert.pose_opengl_to_opencv()`` + +Image Coordinate +---------------- + +Starts from the top-left corner of the image, with :math:`x` pointing right +(corresponding to the image width) and :math:`y` pointing down (corresponding to +the image height). This is consistent with OpenCV. + +Pay attention that the 0th dimension in the image array is the height (i.e., :math:`y`) +and the 1st dimension is the width (i.e., :math:`x`). That is: + +- :math:`x` <=> ``u`` <=> width <=> column <=> the 1st dimension +- :math:`y` <=> ``v`` <=> height <=> row <=> the 0th dimension + +Matrix Definitions +------------------ + +Camera Intrinsic Matrix (K) +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``K`` is a ``(3, 3)`` camera intrinsic matrix: + +.. code-block:: python + + K = [[fx, s, cx], + [ 0, fy, cy], + [ 0, 0, 1]] + +Camera Extrinsic Matrix (T or W2C) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``T`` is a ``(4, 4)`` camera extrinsic matrix: + +.. code-block:: python + + T = [[R | t = [[R00, R01, R02, t0], + 0 | 1]] [R10, R11, R12, t1], + [R20, R21, R22, t2], + [ 0, 0, 0, 1]] + +- ``T`` is also known as the world-to-camera ``W2C`` matrix, which transforms a + point in the world coordinate to the camera coordinate. +- ``T``'s shape is ``(4, 4)``, not ``(3, 4)``. +- ``T`` is the inverse of ``pose``, i.e., ``np.linalg.inv(T) == pose``. +- The camera center ``C`` in world coordinate is projected to ``[0, 0, 0, 1]`` in + camera coordinate. + +Rotation Matrix (R) +^^^^^^^^^^^^^^^^^^^ + +``R`` is a ``(3, 3)`` rotation matrix: + +.. code-block:: python + + R = T[:3, :3] + +- ``R`` is a rotation matrix. It is an orthogonal matrix with determinant 1, as + rotations preserve volume and orientation. + - ``R.T == np.linalg.inv(R)`` + - ``np.linalg.norm(R @ x) == np.linalg.norm(x)``, where ``x`` is a ``(3,)`` vector. + +Translation Vector (t) +^^^^^^^^^^^^^^^^^^^^^^ + +``t`` is a ``(3,)`` translation vector: + +.. code-block:: python + + t = T[:3, 3] + +- ``t``'s shape is ``(3,)``, not ``(3, 1)``. + +Camera Pose Matrix (pose or C2W) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``pose`` is a ``(4, 4)`` camera pose matrix. It is the inverse of ``T``. + +- ``pose`` is also known as the camera-to-world ``C2W`` matrix, which transforms a + point in the camera coordinate to the world coordinate. +- ``pose`` is the inverse of ``T``, i.e., ``pose == np.linalg.inv(T)``. + +Camera Center (C) +^^^^^^^^^^^^^^^^^ + +``C`` is the camera center: + +.. code-block:: python + + C = pose[:3, 3] + +- ``C``'s shape is ``(3,)``, not ``(3, 1)``. +- ``C`` is the camera center in world coordinate. It is also the translation + vector of ``pose``. + +Projection Matrix (P) +^^^^^^^^^^^^^^^^^^^^^ + +``P`` is a ``(3, 4)`` camera projection matrix: + +- ``P`` is the world-to-pixel projection matrix, which projects a point in the + homogeneous world coordinate to the homogeneous pixel coordinate. +- ``P`` is the product of the intrinsic and extrinsic parameters: + + .. code-block:: python + + # P = K @ [R | t] + P = K @ np.hstack([R, t[:, None]]) + +- ``P``'s shape is ``(3, 4)``, not ``(4, 4)``. +- It is possible to decompose ``P`` into intrinsic and extrinsic matrices by QR + decomposition. +- Don't confuse ``P`` with ``pose``. Don't confuse ``P`` with ``T``. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..ee7be984 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,103 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +import os +import sys +import subprocess +import camtools as ct + +sys.path.insert(0, os.path.abspath("..")) + +# Get version from camtools package +version = ct.__version__ + +# Get git commit hash +try: + git_hash = ( + subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]) + .decode("ascii") + .strip() + ) + release = f"{version}+{git_hash}" +except subprocess.CalledProcessError: + release = version + +project = "CamTools" +copyright = "2024, Yixing Lao" +author = "Yixing Lao" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", + "sphinx.ext.intersphinx", + "myst_parser", +] + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +language = "en" + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "furo" +html_static_path = ["_static"] + +# Furo theme options +html_theme_options = { + "light_css_variables": { + "color-brand-primary": "#2962ff", + "color-brand-content": "#2962ff", + }, + "dark_css_variables": { + "color-brand-primary": "#5c85ff", + "color-brand-content": "#5c85ff", + }, +} + +# Intersphinx configuration +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "numpy": ("https://numpy.org/doc/stable/", None), +} + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_init_with_doc = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True +napoleon_type_aliases = None + +# AutoDoc settings +autodoc_member_order = "bysource" +autodoc_typehints = "description" +autodoc_typehints_description_target = "documented" +add_module_names = True +python_use_unqualified_type_names = False + +# Custom module name display +modindex_common_prefix = ["camtools."] # Strip 'camtools.' from module index + +sys.modules["ct"] = ct # Allow using 'ct' as an alias in documentation + +# Suppress specific warnings +suppress_warnings = [ + "toctree.excluded", # Suppress warnings about files not in any toctree +] diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 00000000..28a3dfa1 --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1,40 @@ +Contributing +============ + +Contributing Guidelines +----------------------- + +- Follow `Angular's commit message convention `_ for PRs. + - This applies to PR's title and ultimately the commit messages in ``main``. + - The prefix shall be one of ``build``, ``ci``, ``docs``, ``feat``, ``fix``, ``perf``, ``refactor``, ``test``. + - Use lowercase. +- Format your code with `black `_. This will be enforced by the CI. + +Building Documentation +---------------------- + +To build and view the documentation locally: + +.. code-block:: bash + + # Build the documentation + cd docs + make html + + # Start a local server to view the documentation + python -m http.server 8000 --directory _build/html + +Then open your browser and navigate to ``http://localhost:8000`` to view the documentation. + +Build with CamTools +------------------- + +If you use CamTools in your project, consider adding one of the following +badges to your project. + +.. raw:: html + +

+ Built with CamTools + Built with CamTools +

diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..5d199762 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,150 @@ +CamTools Documentation +====================== + +.. only:: not latex + + .. image:: https://raw.githubusercontent.com/yxlao/camtools/main/camtools/assets/camtools_logo_light.png + :width: 360 + :align: center + :alt: CamTools Logono + :class: only-light + + .. image:: https://raw.githubusercontent.com/yxlao/camtools/main/camtools/assets/camtools_logo_dark.png + :width: 360 + :align: center + :alt: CamTools Logo + :class: only-dark + +.. raw:: html + +

+ Docs | + Repo +

+ +CamTools is a collection of tools for handling cameras in computer vision. It +can be used for plotting, converting, projecting, ray casting, and doing more +with camera parameters. It follows the standard camera coordinate system with +clear and easy-to-use APIs. + +.. only:: not latex + + .. image:: https://raw.githubusercontent.com/yxlao/camtools/main/camtools/assets/camera_coordinates_light.png + :width: 520 + :align: center + :alt: Camera Coordinates + :class: only-light + + .. image:: https://raw.githubusercontent.com/yxlao/camtools/main/camtools/assets/camera_coordinates_dark.png + :width: 520 + :align: center + :alt: Camera Coordinates + :class: only-dark + +.. toctree:: + :maxdepth: 1 + :caption: Docs + + Home + camera + installation + contributing + api + + +What can you do with CamTools? +------------------------------ + +1. Plot cameras +^^^^^^^^^^^^^^^ + +Useful for debugging 3D reconstruction and NeRFs! + +.. code-block:: python + + import camtools as ct + import open3d as o3d + cameras = ct.camera.create_camera_frustums(Ks, Ts) + o3d.visualization.draw_geometries([cameras]) + +.. image:: https://raw.githubusercontent.com/yxlao/camtools/main/camtools/assets/camera_frames.png + :width: 360 + :align: center + :alt: Camera Frames + +2. Convert camera parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + pose = ct.convert.T_to_pose(T) # Convert T to pose + T = ct.convert.pose_to_T(pose) # Convert pose to T + R, t = ct.convert.T_to_R_t(T) # Convert T to R and t + C = ct.convert.pose_to_C(pose) # Convert pose to camera center + K, T = ct.convert.P_to_K_T(P) # Decompose projection matrix P to K and T + # And more... + +3. Projection and ray casting +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + # Project 3D points to pixels. + pixels = ct.project.points_to_pixel(points, K, T) + + # Back-project depth image to 3D points. + points = ct.project.im_depth_to_points(im_depth, K, T) + + # Ray cast a triangle mesh to depth image given the camera parameters. + im_depth = ct.raycast.mesh_to_im_depth(mesh, K, T, height, width) + + # And more... + +4. Image and depth I/O +^^^^^^^^^^^^^^^^^^^^^^ + +Strict type checks and range checks are enforced. The image and depth I/O +APIs are specifically designed to solve the following pain points: + +- Is my image of type ``float32`` or ``uint8``? +- Does it have range ``[0, 1]`` or ``[0, 255]``? +- Is it RGB or BGR? +- Does my image have an alpha channel? +- When saving depth image as integer-based ``.png``, is it correctly scaled? + +.. code-block:: python + + ct.io.imread() + ct.io.imwrite() + ct.io.imread_detph() + ct.io.imwrite_depth() + +5. Command-line tools +^^^^^^^^^^^^^^^^^^^^^ + +The ``ct`` command runs in terminal: + +.. code-block:: bash + + # Crop image boarders. + ct crop-boarders *.png --pad_pixel 10 --skip_cropped --same_crop + + # Draw synchronized bounding boxes interactively. + ct draw-bboxes path/to/a.png path/to/b.png + + # For more command-line tools. + ct --help + +.. raw:: html + +

+ +

+ +6. And more +^^^^^^^^^^^ + +- Solve line intersections +- COLMAP tools +- Points normalization +- And more... diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 00000000..1695a722 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,41 @@ +Installation +============ + +Quick Installation +------------------ + +To install CamTools, simply do: + +.. code-block:: bash + + pip install camtools + +Installation from Source +------------------------ + +Alternatively, you can install CamTools from source with one of the following +methods: + +.. code-block:: bash + + git clone https://github.com/yxlao/camtools.git + cd camtools + + # Installation mode, if you want to use camtools only. + pip install . + + # Editable mode, if you want to modify camtools on the fly. + pip install -e . + + # Editable mode and dev dependencies. + pip install -e .[dev] + + # Help VSCode resolve imports when installed with editable mode. + # https://stackoverflow.com/a/76897706/1255535 + pip install -e .[dev] --config-settings editable_mode=strict + + # Enable torch-related features (e.g. computing image metrics) + pip install camtools[torch] + + # Enable torch-related features in editable mode + pip install -e .[torch] diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..32bb2452 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/pyproject.toml b/pyproject.toml index 124e3ec5..67401617 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,13 @@ dev = [ "pytest-benchmark>=4.0.0", "ipdb", ] +docs = [ + "sphinx", + "sphinx-rtd-theme", + "myst-parser", + "furo", + "tomli", +] torch = [ "torch>=1.8.0", "lpips>=0.1.4",