{"id":50828976,"url":"https://github.com/antoinehabis/torch_contour","last_synced_at":"2026-06-13T21:03:54.757Z","repository":{"id":211116764,"uuid":"728237159","full_name":"antoinehabis/torch_contour","owner":"antoinehabis","description":"python torch library for polygon / contour to image (mask, distance map) processing and more","archived":false,"fork":false,"pushed_at":"2024-10-04T12:22:22.000Z","size":1701,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-07T09:58:03.379Z","etag":null,"topics":["computer-vision","contour","differentiable","distance-map","mask","polygon","toolbox","torch"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antoinehabis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-06T14:16:06.000Z","updated_at":"2025-05-16T14:11:56.000Z","dependencies_parsed_at":"2024-07-23T11:57:07.805Z","dependency_job_id":null,"html_url":"https://github.com/antoinehabis/torch_contour","commit_stats":null,"previous_names":["antoinehabis/torch_contour"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/antoinehabis/torch_contour","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoinehabis%2Ftorch_contour","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoinehabis%2Ftorch_contour/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoinehabis%2Ftorch_contour/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoinehabis%2Ftorch_contour/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antoinehabis","download_url":"https://codeload.github.com/antoinehabis/torch_contour/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoinehabis%2Ftorch_contour/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34300127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computer-vision","contour","differentiable","distance-map","mask","polygon","toolbox","torch"],"created_at":"2026-06-13T21:03:54.113Z","updated_at":"2026-06-13T21:03:54.737Z","avatar_url":"https://github.com/antoinehabis.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# torch_contour\n\n![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge\u0026logo=python\u0026logoColor=ffdd54)\n[![Mail](https://img.shields.io/badge/Gmail-D14836?style=for-the-badge\u0026logo=gmail\u0026logoColor=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\u003cfigure\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg \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\"\u003e\n  \u003cfigcaption\u003e 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\u003c/figcaption\u003e\n\u003c/p\u003e\n\u003c/figure\u003e\n\u003c!-- ![](https://github.com/antoinehabis/torch_contour/blob/main/vary_nodes.jpg?raw=True) --\u003e\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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoinehabis%2Ftorch_contour","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantoinehabis%2Ftorch_contour","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoinehabis%2Ftorch_contour/lists"}