Metadata-Version: 2.4
Name: skeleton_refinement
Version: 0.1.3
Summary: Skeletonization of Plant Point Cloud Data Using Stochastic Optimization Framework.
Author-email: Ayan Chaudhury <ayanchaudhury.cs@gmail.com>, Christophe Godin <christophe.godin@inria.fr>
Maintainer-email: Jonathan Legrand <jonathan.legrand@ens-lyon.fr>
License-Expression: GPL-3.0-or-later
Project-URL: homepage, https://romi-project.eu/
Project-URL: documentation, https://docs.romi-project.eu/plant_imager/
Project-URL: source, https://github.com/romi/skeleton_refinement
Project-URL: issues, https://github.com/romi/skeleton_refinement/issues
Keywords: Robotics for Microfarms,ROMI,Skeleton,Point-cloud,Stochastic Optimization,Gaussian Mixture Models,Expectation Maximization
Classifier: Programming Language :: Python :: 3
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Operating System :: OS Independent
Classifier: Natural Language :: English
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: matplotlib
Requires-Dist: networkx
Requires-Dist: numpy
Requires-Dist: plyfile
Requires-Dist: psutil
Requires-Dist: pyvista
Requires-Dist: scikit-learn
Requires-Dist: tqdm
Provides-Extra: doc
Requires-Dist: mkdocs; extra == "doc"
Requires-Dist: mkdocs-material; extra == "doc"
Requires-Dist: mkdocstrings[python]; extra == "doc"
Requires-Dist: pymdown-extensions; extra == "doc"
Requires-Dist: markdown-exec[ansi]; extra == "doc"
Requires-Dist: mkdocs-gen-files; extra == "doc"
Requires-Dist: mkdocs-literate-nav; extra == "doc"
Requires-Dist: mkdocs-section-index; extra == "doc"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: nb
Requires-Dist: notebook; extra == "nb"
Requires-Dist: ipywidgets; extra == "nb"
Requires-Dist: plotly; extra == "nb"
Dynamic: license-file

# [![ROMI_logo](docs/assets/images/ROMI_logo_green_25.svg)](https://romi-project.eu) / Skeleton Refinement

[![Licence](https://img.shields.io/github/license/romi/skeleton_refinement?color=lightgray)](https://www.gnu.org/licenses/gpl-3.0.en.html)
[![Python Version](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fromi%2Fskeleton_refinement%2Frefs%2Fheads%2Fmain%2Fpyproject.toml&logo=python&logoColor=white)]()
[![PyPI - Version](https://img.shields.io/pypi/v/skeleton_refinement?logo=pypi&logoColor=white)](https://pypi.org/project/skeleton_refinement/)
[![Conda - Version](https://img.shields.io/conda/vn/romi-eu/skeleton_refinement?logo=anaconda&logoColor=white&label=romi-eu&color=%2344A833)](https://anaconda.org/romi-eu/skeleton_refinement)
[![GitHub branch check runs](https://img.shields.io/github/check-runs/romi/skeleton_refinement/main)](https://github.com/romi/skeleton_refinement)


The documentation of the _Plant Imager_ project can be found here: https://docs.romi-project.eu/plant_imager/

The API documentation of the `skeleton_refinement` library can be found here: https://romi.github.io/skeleton_refinement/ 

## About

This library is intended to provide the implementation of a skeleton refinement method published here:

Chaudhury A. and Godin C. (2020) **Skeletonization of Plant Point Cloud Data Using Stochastic Optimization Framework**.
_Front. Plant Sci._ 11:773.
DOI: [10.3389/fpls.2020.00773](https://doi.org/10.3389/fpls.2020.00773).

![Skeleton refinement result on arabidopsis data.](docs/assets/images/arabidopsis_example.png)

This is a part of the implementation of the stochastic registration algorithm based on the following paper:
Myronenko A. and Song X. (2010) **Point set registration: Coherent Point drift**.
_IEEE Transactions on Pattern Analysis and Machine Intelligence_. 32 (2): 2262-2275.
DOI: [10.1109/TPAMI.2010.46](https://doi.org/10.1109/TPAMI.2010.46).
arXiv [PDF](https://arxiv.org/pdf/0905.2635).

The library is based on the Python implementation of the paper in ``pycpd`` package.
[GitHub](https://github.com/siavashk/pycpd) sources.
[PyPi](https://pypi.org/project/pycpd/) package.


## Installation

We strongly advise creating isolated environments to install the ROMI libraries.

We often use `conda` as an environment and Python package manager.
If you do not yet have `miniconda3` installed on your system, have a look [here](https://docs.conda.io/en/latest/miniconda.html).

The `skeleton_refinement` package is available from the `romi-eu` channel.

### Existing conda environment
To install the `skeleton_refinement` conda package in an existing environment, first activate it, then proceed as follows:
```shell
conda install skeleton_refinement -c romi-eu
```

### New conda environment
To install the `skeleton_refinement` conda package in a new environment, here named `romi`, proceed as follows:
```shell
conda create -n romi skeleton_refinement -c romi-eu
```

### Installation from sources
To install this library, clone the repo and use `pip` to install it and the required dependencies.
Again, we strongly advise creating a `conda` environment.

All this can be done as follows:
```shell
git clone https://github.com/romi/skeleton_refinement.git
cd skeleton_refinement
conda create -n skeleton_refinement 'python =3.10' ipython
conda activate skeleton_refinement  # do not forget to activate your environment!
python -m pip install -e .  # install the sources
```

Note that the `-e` option is to install the `skeleton_refinement` sources in "developer mode".
That is, if you make changes to the source code of `skeleton_refinement` you will not have to `pip install` it again.


## Usage

### Example dataset

First, we download an example dataset from Zenodo, named `real_plant_analyzed`, to play with:

```shell
wget https://zenodo.org/records/10379172/files/real_plant_analyzed.zip
unzip real_plant_analyzed.zip -d /tmp
```

It contains:
  * a plant point cloud under `PointCloud_1_0_1_0_10_0_7ee836e5a9/PointCloud.ply`
  * a plant skeleton under `CurveSkeleton__TriangleMesh_0393cb5708/CurveSkeleton.json`
  * a plant tree graph under `TreeGraph__False_CurveSkeleton_c304a2cc71/TreeGraph.p`


### CLI

You may use the `refine_skeleton` CLI to refine a given skeleton using the original point cloud: 

```shell
export DATA_PATH="/tmp/real_plant_analyzed"
refine_skeleton \
  ${DATA_PATH}/PointCloud_1_0_1_0_10_0_7ee836e5a9/PointCloud.ply \
  ${DATA_PATH}/CurveSkeleton__TriangleMesh_0393cb5708/CurveSkeleton.json \
  ${DATA_PATH}/optimized_skeleton.txt
```

### Python API

Here is a minimal example of how to use the `skeleton_refinement` library in Python:

```python
from skeleton_refinement.stochastic_registration import perform_registration
from skeleton_refinement.io import load_json, load_ply

pcd = load_ply("/tmp/real_plant_analyzed/PointCloud_1_0_1_0_10_0_7ee836e5a9/PointCloud.ply")
skel = load_json("/tmp/real_plant_analyzed/CurveSkeleton__TriangleMesh_0393cb5708/CurveSkeleton.json", "points")
# Perform stochastic optimization
refined_skel = perform_registration(pcd, skel)

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter(*pcd.T, marker='.', color='black')
ax.scatter(*skel.T, marker='o', color='r')
ax.scatter(*refined_skel.T, marker='o', color='b')
ax.set_aspect('equal')
plt.show()
```

Detailed documentation of the Python API is available here: https://romi.github.io/skeleton_refinement/reference.html

## Git LFS & package data

Large binary assets (_e.g._, point‑cloud files) are stored with **Git Large File Storage (LFS)**.
To make sure you have the required data locally, follow the steps below.

### 1. Install Git LFS (once per machine)

```shell
# macOS (Homebrew)
brew install git-lfs

# Ubuntu/Debian
sudo apt-get install git-lfs

# Windows (Chocolatey)
choco install git-lfs
```

After installation, run the global initializer:

```shell
git lfs install
```

*(You only need to run `git lfs install` the first time you use LFS on a machine.)*

### 2. Pull (or refresh) LFS data after cloning or after a `git pull`

If you already have the repository cloned and want to make sure all LFS objects are present:

```shell
git lfs pull            # Downloads only the missing LFS objects
# or, to fetch *all* LFS blobs for every branch/tag:
git lfs fetch --all
git lfs checkout        # Replace pointers with real files
```

### 3. Verify that large files are present

```shell
git lfs ls-files
```

You should see a list of tracked files with their SHA‑256 hashes, confirming that the real content is on disk.

## Developers & contributors

### Adding new large files

If you add a new large file, LFS should handle that.
Let's assume you want to add a PLY point-cloud:

```shell
git lfs track "*.ply"   # Example for point‑cloud files
git commit -m "Add a new large point‑cloud file via Git LFS"
git push
```
Git LFS will automatically upload the file to the LFS storage associated with the repository.

### Unitary tests

Some tests are defined in the `tests` directory.
We use `nose2` to call them as follows:

```shell
nose2 -v -C
```

### Conda packaging

The repository provides a **conda_build** GitHub Actions workflow (`.github/workflows/conda.yml`).  
It runs automatically when a new release is published **or** can be triggered manually from the Actions tab.

#### Build a conda package locally

Start by installing the required `conda-build` & `anaconda-client` conda packages in the `base` environment as follows:
```shell
conda install -n base conda-build anaconda-client
```

To build the `skeleton_refinement` conda package locally, from the root directory of the repository and the `base` conda environment, run:
```shell
conda build conda/recipe/ -c conda-forge --user romi-eu
```

If you need to inspect the rendered recipe before building, you can render it with:
```shell
conda render conda/recipe/
```

The official documentation for `conda-render` can be found [here](https://docs.conda.io/projects/conda-build/en/stable/resources/commands/conda-render.html).

#### Upload a conda package

To upload the built package, you need a valid account (here `romi-eu`) on [anaconda.org](www.anaconda.org) & to log ONCE
with `anaconda login`, then:
```shell
anaconda upload ~/miniconda3/conda-bld/linux-64/skeleton_refinement*.tar.bz2 --user romi-eu
```

#### Clean builds

To clean the source and build intermediates:
```shell
conda build purge
```

To clean **ALL** the built packages & build environments:
```shell
conda build purge-all
```

### PyPi packaging

The repository includes a GitHub Actions workflow (`.github/workflows/pip_build.yml`) that builds the package and publishes it to **PyPI** automatically on each release.

#### Build the distribution

The GitHub Actions workflow builds the package using `python -m build`, generating both source (`sdist`) and wheel (`bdist_wheel`) archives in the `dist/` folder.

You can run the same command locally:
```shell
python -m build
```

#### Publish to PyPI

For releases, the workflow uses the trusted publishing action `pypa/gh-action-pypi-publish` to upload the artifacts from `dist/` to PyPI.

If you need to publish manually, you can use `twine`:
```shell
twine upload dist/*
```

> **Note:** Ensure that the `pypi` environment in your GitHub repository is configured with a valid PyPI API token (or use the built‑in trusted publishing mechanism).
