# torch_contour
![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)
[![Mail](https://img.shields.io/badge/Gmail-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:antoine.habis.tlcm@gmail.com)
[![Downloads](https://static.pepy.tech/badge/torch_contour/month)](https://pepy.tech/project/torch_contour)
[![Downloads](https://static.pepy.tech/badge/torch_contour)](https://pepy.tech/project/torch_contour)
[![ArXiv Paper](https://img.shields.io/badge/DOI-10.1038%2Fs41586--020--2649--2-blue)](
https://doi.org/10.48550/arXiv.2407.10696)
<figure>
<p align="center">
<img
src="https://github.com/antoinehabis/torch_contour/blob/main/vary_nodes.jpg?raw=True"
alt="Example of torch contour on a circle when varying the number of nodes"
width="500">
<figcaption> Example of output of contour to mask and contour to distance map on a polygon in the form of a circle when varying the number of nodes</figcaption>
</p>
</figure>
<!-- ![](https://github.com/antoinehabis/torch_contour/blob/main/vary_nodes.jpg?raw=True) -->
# Download
```
$pip install torch_contour
```
# Overview of the Toolbox
1. Pytorch layers for differentiable contour (polygon) to image operations.
* Contour to mask
* Contour to distance map
* Draw contour
* Contour to isolines
* Smooth contour
if using the layers above please cite the following paper:
```
@misc{habis2024deepcontourflowadvancingactive,
title={Deep ContourFlow: Advancing Active Contours with Deep Learning},
author={Antoine Habis and Vannary Meas-Yedid and Elsa Angelini and Jean-Christophe Olivo-Marin},
year={2024},
eprint={2407.10696},
archivePrefix={arXiv},
primaryClass={cs.CV},
url={https://arxiv.org/abs/2407.10696},
}
```
2. Pytorch functions for contour feature extraction.
* Area
* Perimeter
* Curvature
* Hausdorff distance
3. Function for NumPy arrays only to remove loops inside contours and interpolate along the given contours.
# Pytorch Layers
This library contains 3 pytorch non trainable layers for performing the differentiable operations of :
1. Contour to mask
2. Contour to distance map.
3. Draw contour.
4. Contour to isolines
5. Smooth contour
It can therefore be used to transform a polygon into a binary mask/distance map/ drawn contour in a completely differentiable way.\
In particular, it can be used to transform the detection task into a segmentation task or do detection with any polygon.\
The layers in 1, 2, 3 use the nice property of polygons such that for any point inside the sum of oriented angle is $\pm 2\pi$ and quickly converge towards 0 outside.\
The three layers have no learnable weight.\
All they do is to apply a function in a differentiable way.
## Input (Float) (layer 1, 2, 3, 4, 5):
A list of polygons of shape $B \times N \times K \times 2$ with:
* $B$ the batch size
* $N$ the number of polygons for each image
* $K$ the number of nodes for each polygon
## Output (Float) (layer 1, 2, 3):
A mask/distance map/contour drawn of shape $B \times N \times H \times H$ with :
* $B$ the batch size
* $N$ the number of polygons for each image
* $H$ the Heigh of the distance map or mask
## Output (Float) (layer 4):
Isolines of shape $B \times N \times I \times H \times H$ with :
* $B$ the batch size
* $N$ the number of polygons for each image
* $I$ the number of isolines to extract for each image
* $H$ the Heigh of the distance map or mask
## Output (Float) (layer 5):
Contours of shape $B \times N \times K \times 2$ with :
* $B$ the batch size
* $N$ the number of polygons for each image
* $K$ the number of nodes for each polygon
## Important:
The polygon must have values between 0 and 1.
## Example:
```
from torch_contour.torch_contour import Contour_to_distance_map,Contour_to_isolines, Contour_to_mask, Draw_contour, Smoothing, CleanContours
import torch
import matplotlib.pyplot as plt
polygons1 = torch.tensor(
[
[
[
[0.1640, 0.5085],
[0.1267, 0.4491],
[0.1228, 0.3772],
[0.1461, 0.3027],
[0.1907, 0.2356],
[0.2503, 0.1857],
[0.3190, 0.1630],
[0.3905, 0.1774],
[0.4595, 0.2317],
[0.5227, 0.3037],
[0.5774, 0.3658],
[0.6208, 0.3905],
[0.6505, 0.3513],
[0.6738, 0.2714],
[0.7029, 0.2152],
[0.7461, 0.2298],
[0.8049, 0.2828],
[0.8776, 0.3064],
[0.9473, 0.2744],
[0.9606, 0.2701],
[0.9138, 0.3192],
[0.8415, 0.3947],
[0.7793, 0.4689],
[0.7627, 0.5137],
[0.8124, 0.5142],
[0.8961, 0.5011],
[0.9696, 0.5158],
[1.0000, 0.5795],
[0.9858, 0.6581],
[0.9355, 0.7131],
[0.9104, 0.7682],
[0.9184, 0.8406],
[0.8799, 0.8974],
[0.8058, 0.9121],
[0.7568, 0.8694],
[0.7305, 0.7982],
[0.6964, 0.7466],
[0.6378, 0.7394],
[0.5639, 0.7597],
[0.4864, 0.7858],
[0.4153, 0.7953],
[0.3524, 0.7609],
[0.3484, 0.7028],
[0.3092, 0.7089],
[0.2255, 0.7632],
[0.1265, 0.8300],
[0.0416, 0.8736],
[0.0000, 0.8584],
[0.0310, 0.7486],
[0.1640, 0.5085],
]
]
],
dtype=torch.float32,
)
width = 200
Mask = Contour_to_mask(width)
Draw = Draw_contour(width)
Dmap = Contour_to_distance_map(width)
Iso = Contour_to_isolines(width, isolines=[0.1, 0.5, 1])
smoother = Smoothing(sigma=1)
mask = Mask(polygons1).cpu().detach().numpy()[0, 0]
draw = Draw(polygons1).cpu().detach().numpy()[0, 0]
distance_map = Dmap(polygons1).cpu().detach().numpy()[0, 0]
isolines = Iso(polygons1).cpu().detach().numpy()[0, 0]
contour_smooth = smoother(polygons1)
plt.imshow(mask)
plt.show()
plt.imshow(draw)
plt.show()
plt.imshow(distance_map)
plt.show()
plt.imshow(isolines[1])
plt.show()
```
# Pytorch functions
This library also contains batch torch operations for performing:
1. The area of a batch of polygons
2. The perimeter of a batch of polygons
3. The curvature of a batch of polygons
4. The haussdorf distance between 2 sets of polygons
```
from torch_contour.torch_contour import area, perimeter, hausdorff_distance, curvature
import torch
polygons2 = torch.tensor([[[[0.0460, 0.3955],
[0.0000, 0.2690],
[0.0179, 0.1957],
[0.0789, 0.1496],
[0.1622, 0.1049],
[0.2495, 0.0566],
[0.3287, 0.0543],
[0.3925, 0.1280],
[0.4451, 0.2231],
[0.4928, 0.2692],
[0.5436, 0.2215],
[0.6133, 0.1419],
[0.7077, 0.1118],
[0.7603, 0.1569],
[0.7405, 0.2511],
[0.6742, 0.3440],
[0.6042, 0.4099],
[0.6036, 0.4780],
[0.6693, 0.5520],
[0.7396, 0.6100],
[0.8190, 0.6502],
[0.9172, 0.6815],
[0.9818, 0.7310],
[0.9605, 0.8186],
[0.8830, 0.9023],
[0.8048, 0.9205],
[0.7506, 0.8514],
[0.6597, 0.7975],
[0.5866, 0.8195],
[0.5988, 0.9145],
[0.6419, 1.0000],
[0.6529, 0.9978],
[0.6253, 0.9186],
[0.5714, 0.8027],
[0.5035, 0.6905],
[0.4340, 0.6223],
[0.3713, 0.6260],
[0.3116, 0.6854],
[0.2478, 0.7748],
[0.1732, 0.8687],
[0.0892, 0.9420],
[0.0353, 0.9737],
[0.0452, 0.9514],
[0.1028, 0.8855],
[0.1831, 0.7907],
[0.2610, 0.6817],
[0.3113, 0.5730],
[0.3090, 0.4793],
[0.2289, 0.4153],
[0.0460, 0.3955]]]], dtype = torch.float32)
area_ = area(polygons2)
perimeter_ = perimeter(polygons2)
curvs = curvature(polygons2)
hausdorff_dists = hausdorff_distance(polygons1, polygons2)
```
# NumPy remove loops and interpolate
```
cleaner = CleanContours()
cleaned_contours = cleaner.clean_contours(polygons2.cpu().detach().numpy())
cleaned_interpolated_contours = cleaner.clean_contours_and_interpolate(polygons2.cpu().detach().numpy())
```
Raw data
{
"_id": null,
"home_page": "https://github.com/antoinehabis/torch_contour",
"name": "torch-contour",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "differentiable contour processing, pytorch, machine learning, polygon, shape, mask, distance map, draw contour, hausdorff distance",
"author": "Antoine Habis",
"author_email": "antoine.habis.tlcm@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/35/8f/1d302b8e38c9fccc0e7531f6574ac267819ad96191471a1eaa58fc841b5a/torch_contour-1.3.0.tar.gz",
"platform": null,
"description": "# torch_contour\n\n![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)\n[![Mail](https://img.shields.io/badge/Gmail-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:antoine.habis.tlcm@gmail.com)\n[![Downloads](https://static.pepy.tech/badge/torch_contour/month)](https://pepy.tech/project/torch_contour)\n[![Downloads](https://static.pepy.tech/badge/torch_contour)](https://pepy.tech/project/torch_contour)\n[![ArXiv Paper](https://img.shields.io/badge/DOI-10.1038%2Fs41586--020--2649--2-blue)](\nhttps://doi.org/10.48550/arXiv.2407.10696)\n\n\n<figure>\n<p align=\"center\">\n <img \n src=\"https://github.com/antoinehabis/torch_contour/blob/main/vary_nodes.jpg?raw=True\"\n alt=\"Example of torch contour on a circle when varying the number of nodes\"\n width=\"500\">\n <figcaption> Example of output of contour to mask and contour to distance map on a polygon in the form of a circle when varying the number of nodes</figcaption>\n</p>\n</figure>\n<!-- ![](https://github.com/antoinehabis/torch_contour/blob/main/vary_nodes.jpg?raw=True) -->\n\n# Download\n\n```\n$pip install torch_contour\n```\n\n# Overview of the Toolbox \n\n1. Pytorch layers for differentiable contour (polygon) to image operations.\n\n * Contour to mask \n * Contour to distance map\n * Draw contour\n * Contour to isolines\n * Smooth contour\n\nif using the layers above please cite the following paper:\n```\n@misc{habis2024deepcontourflowadvancingactive,\n title={Deep ContourFlow: Advancing Active Contours with Deep Learning}, \n author={Antoine Habis and Vannary Meas-Yedid and Elsa Angelini and Jean-Christophe Olivo-Marin},\n year={2024},\n eprint={2407.10696},\n archivePrefix={arXiv},\n primaryClass={cs.CV},\n url={https://arxiv.org/abs/2407.10696}, \n}\n```\n\n2. Pytorch functions for contour feature extraction.\n\n * Area\n * Perimeter\n * Curvature\n * Hausdorff distance\n\n3. Function for NumPy arrays only to remove loops inside contours and interpolate along the given contours.\n\n\n# Pytorch Layers\n\nThis library contains 3 pytorch non trainable layers for performing the differentiable operations of :\n\n1. Contour to mask\n2. Contour to distance map.\n3. Draw contour.\n4. Contour to isolines\n5. Smooth contour\n\n\nIt can therefore be used to transform a polygon into a binary mask/distance map/ drawn contour in a completely differentiable way.\\\nIn particular, it can be used to transform the detection task into a segmentation task or do detection with any polygon.\\\nThe layers in 1, 2, 3 use the nice property of polygons such that for any point inside the sum of oriented angle is $\\pm 2\\pi$ and quickly converge towards 0 outside.\\\nThe three layers have no learnable weight.\\\nAll they do is to apply a function in a differentiable way.\n\n\n\n## Input (Float) (layer 1, 2, 3, 4, 5):\n\nA list of polygons of shape $B \\times N \\times K \\times 2$ with:\n* $B$ the batch size\n* $N$ the number of polygons for each image\n* $K$ the number of nodes for each polygon\n\n\n## Output (Float) (layer 1, 2, 3):\n\nA mask/distance map/contour drawn of shape $B \\times N \\times H \\times H$ with :\n* $B$ the batch size\n* $N$ the number of polygons for each image\n* $H$ the Heigh of the distance map or mask\n\n\n## Output (Float) (layer 4):\n\nIsolines of shape $B \\times N \\times I \\times H \\times H$ with :\n* $B$ the batch size\n* $N$ the number of polygons for each image\n* $I$ the number of isolines to extract for each image\n* $H$ the Heigh of the distance map or mask\n\n## Output (Float) (layer 5):\n\nContours of shape $B \\times N \\times K \\times 2$ with :\n* $B$ the batch size\n* $N$ the number of polygons for each image\n* $K$ the number of nodes for each polygon\n\n## Important: \n\nThe polygon must have values between 0 and 1. \n\n\n## Example:\n\n ```\nfrom torch_contour.torch_contour import Contour_to_distance_map,Contour_to_isolines, Contour_to_mask, Draw_contour, Smoothing, CleanContours\nimport torch\nimport matplotlib.pyplot as plt\n\npolygons1 = torch.tensor(\n [\n [\n [\n [0.1640, 0.5085],\n [0.1267, 0.4491],\n [0.1228, 0.3772],\n [0.1461, 0.3027],\n [0.1907, 0.2356],\n [0.2503, 0.1857],\n [0.3190, 0.1630],\n [0.3905, 0.1774],\n [0.4595, 0.2317],\n [0.5227, 0.3037],\n [0.5774, 0.3658],\n [0.6208, 0.3905],\n [0.6505, 0.3513],\n [0.6738, 0.2714],\n [0.7029, 0.2152],\n [0.7461, 0.2298],\n [0.8049, 0.2828],\n [0.8776, 0.3064],\n [0.9473, 0.2744],\n [0.9606, 0.2701],\n [0.9138, 0.3192],\n [0.8415, 0.3947],\n [0.7793, 0.4689],\n [0.7627, 0.5137],\n [0.8124, 0.5142],\n [0.8961, 0.5011],\n [0.9696, 0.5158],\n [1.0000, 0.5795],\n [0.9858, 0.6581],\n [0.9355, 0.7131],\n [0.9104, 0.7682],\n [0.9184, 0.8406],\n [0.8799, 0.8974],\n [0.8058, 0.9121],\n [0.7568, 0.8694],\n [0.7305, 0.7982],\n [0.6964, 0.7466],\n [0.6378, 0.7394],\n [0.5639, 0.7597],\n [0.4864, 0.7858],\n [0.4153, 0.7953],\n [0.3524, 0.7609],\n [0.3484, 0.7028],\n [0.3092, 0.7089],\n [0.2255, 0.7632],\n [0.1265, 0.8300],\n [0.0416, 0.8736],\n [0.0000, 0.8584],\n [0.0310, 0.7486],\n [0.1640, 0.5085],\n ]\n ]\n ],\n dtype=torch.float32,\n)\n\nwidth = 200\n\nMask = Contour_to_mask(width)\nDraw = Draw_contour(width)\nDmap = Contour_to_distance_map(width)\nIso = Contour_to_isolines(width, isolines=[0.1, 0.5, 1])\nsmoother = Smoothing(sigma=1)\n\nmask = Mask(polygons1).cpu().detach().numpy()[0, 0]\ndraw = Draw(polygons1).cpu().detach().numpy()[0, 0]\ndistance_map = Dmap(polygons1).cpu().detach().numpy()[0, 0]\nisolines = Iso(polygons1).cpu().detach().numpy()[0, 0]\ncontour_smooth = smoother(polygons1)\n\nplt.imshow(mask)\nplt.show()\nplt.imshow(draw)\nplt.show()\nplt.imshow(distance_map)\nplt.show()\nplt.imshow(isolines[1])\nplt.show()\n```\n\n# Pytorch functions\n\nThis library also contains batch torch operations for performing:\n\n1. The area of a batch of polygons\n2. The perimeter of a batch of polygons\n3. The curvature of a batch of polygons\n4. The haussdorf distance between 2 sets of polygons\n\n\n ```\nfrom torch_contour.torch_contour import area, perimeter, hausdorff_distance, curvature\nimport torch\n\n\npolygons2 = torch.tensor([[[[0.0460, 0.3955],\n [0.0000, 0.2690],\n [0.0179, 0.1957],\n [0.0789, 0.1496],\n [0.1622, 0.1049],\n [0.2495, 0.0566],\n [0.3287, 0.0543],\n [0.3925, 0.1280],\n [0.4451, 0.2231],\n [0.4928, 0.2692],\n [0.5436, 0.2215],\n [0.6133, 0.1419],\n [0.7077, 0.1118],\n [0.7603, 0.1569],\n [0.7405, 0.2511],\n [0.6742, 0.3440],\n [0.6042, 0.4099],\n [0.6036, 0.4780],\n [0.6693, 0.5520],\n [0.7396, 0.6100],\n [0.8190, 0.6502],\n [0.9172, 0.6815],\n [0.9818, 0.7310],\n [0.9605, 0.8186],\n [0.8830, 0.9023],\n [0.8048, 0.9205],\n [0.7506, 0.8514],\n [0.6597, 0.7975],\n [0.5866, 0.8195],\n [0.5988, 0.9145],\n [0.6419, 1.0000],\n [0.6529, 0.9978],\n [0.6253, 0.9186],\n [0.5714, 0.8027],\n [0.5035, 0.6905],\n [0.4340, 0.6223],\n [0.3713, 0.6260],\n [0.3116, 0.6854],\n [0.2478, 0.7748],\n [0.1732, 0.8687],\n [0.0892, 0.9420],\n [0.0353, 0.9737],\n [0.0452, 0.9514],\n [0.1028, 0.8855],\n [0.1831, 0.7907],\n [0.2610, 0.6817],\n [0.3113, 0.5730],\n [0.3090, 0.4793],\n [0.2289, 0.4153],\n [0.0460, 0.3955]]]], dtype = torch.float32) \n\n\narea_ = area(polygons2)\nperimeter_ = perimeter(polygons2)\ncurvs = curvature(polygons2)\nhausdorff_dists = hausdorff_distance(polygons1, polygons2)\n\n```\n\n# NumPy remove loops and interpolate\n\n```\ncleaner = CleanContours()\ncleaned_contours = cleaner.clean_contours(polygons2.cpu().detach().numpy())\ncleaned_interpolated_contours = cleaner.clean_contours_and_interpolate(polygons2.cpu().detach().numpy())\n```\n\n\n\n\n\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Differentiable contour to image operations with PyTorch",
"version": "1.3.0",
"project_urls": {
"Homepage": "https://github.com/antoinehabis/torch_contour"
},
"split_keywords": [
"differentiable contour processing",
" pytorch",
" machine learning",
" polygon",
" shape",
" mask",
" distance map",
" draw contour",
" hausdorff distance"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "46a3cd7df79dc5041158370c7203083d178bdda0c8e5a7579e95d8649b281582",
"md5": "8e44e38ffafaf26a10e5b87a50a929ff",
"sha256": "0930fc4666bfc35b257ddd85d89671ea0bc369c5c7caa88e03686dc6a59dbf31"
},
"downloads": -1,
"filename": "torch_contour-1.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8e44e38ffafaf26a10e5b87a50a929ff",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 11658,
"upload_time": "2024-10-02T12:19:26",
"upload_time_iso_8601": "2024-10-02T12:19:26.460532Z",
"url": "https://files.pythonhosted.org/packages/46/a3/cd7df79dc5041158370c7203083d178bdda0c8e5a7579e95d8649b281582/torch_contour-1.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "358f1d302b8e38c9fccc0e7531f6574ac267819ad96191471a1eaa58fc841b5a",
"md5": "55760705c4f202b1152625aaa77540fe",
"sha256": "ed8e0e2117f440a4a2e2652337cc7accc44a49c1c0c04c423ca2510edbf093f3"
},
"downloads": -1,
"filename": "torch_contour-1.3.0.tar.gz",
"has_sig": false,
"md5_digest": "55760705c4f202b1152625aaa77540fe",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 14315,
"upload_time": "2024-10-02T12:19:27",
"upload_time_iso_8601": "2024-10-02T12:19:27.647436Z",
"url": "https://files.pythonhosted.org/packages/35/8f/1d302b8e38c9fccc0e7531f6574ac267819ad96191471a1eaa58fc841b5a/torch_contour-1.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-02 12:19:27",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "antoinehabis",
"github_project": "torch_contour",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "torch-contour"
}