{"id":28385991,"url":"https://github.com/openstitching/lir","last_synced_at":"2025-10-05T17:06:03.532Z","repository":{"id":42514205,"uuid":"439271875","full_name":"OpenStitching/lir","owner":"OpenStitching","description":"Largest Interior/Inscribed Rectangle implementation in Python. ","archived":false,"fork":false,"pushed_at":"2025-09-22T20:53:59.000Z","size":298,"stargazers_count":181,"open_issues_count":7,"forks_count":21,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-22T22:26:42.631Z","etag":null,"topics":["inscribed","interior","largest","python","rectangle"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenStitching.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":null,"patreon":null,"open_collective":"openstitching","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2021-12-17T09:04:41.000Z","updated_at":"2025-09-03T18:01:02.000Z","dependencies_parsed_at":"2023-01-26T12:46:35.735Z","dependency_job_id":"dec6a72e-ab77-435e-a906-aae1226dc771","html_url":"https://github.com/OpenStitching/lir","commit_stats":null,"previous_names":["lukasalexanderweber/lir"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/OpenStitching/lir","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenStitching%2Flir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenStitching%2Flir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenStitching%2Flir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenStitching%2Flir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenStitching","download_url":"https://codeload.github.com/OpenStitching/lir/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenStitching%2Flir/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278486308,"owners_count":25994945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"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":["inscribed","interior","largest","python","rectangle"],"created_at":"2025-05-30T12:38:05.597Z","updated_at":"2025-10-05T17:06:03.515Z","avatar_url":"https://github.com/OpenStitching.png","language":"Python","readme":"# lir\n\nFast Largest Interior Rectangle calculation within a binary grid.\n\n![sample1](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/sample1.png?raw=true)\n\n:rocket: Through [Numba](https://github.com/numba/numba) the Python code is\ncompiled to machine code for execution at native machine code speed!\n\n## Installation\n\nUse pip to install largestinteriorrectangle from [PyPI](https://pypi.org/project/largestinteriorrectangle/).\n\n```bash\npip install largestinteriorrectangle\n```\n\n:snail: Compiling the code takes some time (~1 minute on my computer).\nThis is only required once after installation,\nthe compiled code is then cached.\nIf you want to do this outside your application, open a Python console\nand type `import largestinteriorrectangle`.\nYou will see the console block for some time. When it is done\na second import will only take milliseconds.\n\n## Usage\n\n```python\nimport largestinteriorrectangle as lir\nimport numpy as np\n\ngrid = np.array([[0, 0, 1, 0, 0, 0, 0, 0, 0],\n                 [0, 0, 1, 0, 1, 1, 0, 0, 0],\n                 [0, 0, 1, 1, 1, 1, 1, 0, 0],\n                 [0, 0, 1, 1, 1, 1, 1, 1, 0],\n                 [0, 0, 1, 1, 1, 1, 1, 1, 0],\n                 [0, 1, 1, 1, 1, 1, 1, 0, 0],\n                 [0, 0, 1, 1, 1, 1, 0, 0, 0],\n                 [0, 0, 1, 1, 1, 1, 0, 0, 0],\n                 [1, 1, 1, 1, 1, 1, 0, 0, 0],\n                 [1, 1, 0, 0, 0, 1, 1, 1, 1],\n                 [0, 0, 0, 0, 0, 0, 0, 0, 0]],\n                \"bool\")\n\nlir.lir(grid) # array([2, 2, 4, 7])\n```\n\nFor [significant performance enhancement](#lir-based-on-contour)\nin larger grids specify the contours(s) of the polygons to consider.\nIf the grid only has one polygon like in the example the contour can\nbe obtained as so (with [opencv](https://pypi.org/project/opencv-python/)).\n\n```python\nimport cv2 as cv\ncv_grid = grid.astype(\"uint8\") * 255\ncontours, _ = \\\n    cv.findContours(cv_grid, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)\ncontour = contours[0][:, 0, :]\n```\n\nthen calculate the rectangle.\n\n```python\nlir.lir(grid, contour) # array([2, 2, 4, 7])\n```\n\nYou can also calculate the lir from a list of polygon coordinates.\n\n```python\nimport numpy as np\nimport cv2 as cv\nimport largestinteriorrectangle as lir\n\npolygon = np.array([[[20, 15], [210, 10], [220, 100], [100, 150], [20, 100]]], np.int32)\nrectangle = lir.lir(polygon)\n\nimg = np.zeros((160, 240, 3), dtype=\"uint8\")\n\ncv.polylines(img, [polygon], True, (0, 0, 255), 1)\ncv.rectangle(img, lir.pt1(rectangle), lir.pt2(rectangle), (255, 0, 0), 1)\n\ncv.imshow('lir', img)\ncv.waitKey(0)\ncv.destroyAllWindows()\n```\n\n![from_polygon](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/from_polygon.png?raw=true)\n\nIn the background, a grid is created with `cv.fillPoly`\n(OpenCV is needed as optional dependency),\non which the contour is computed and the lir based on contour is used.\n\nSee also my [answer in this SO question](https://stackoverflow.com/questions/70362355/finding-largest-inscribed-rectangle-in-polygon/74736411#74736411).\n\n## Contributing\n\nPull requests are welcome. For major changes,\nplease open an issue first to discuss what you would like to change.\n\nPlease make sure to update tests as appropriate.\n\nRun tests using\n\n```bash\npython -m unittest\n```\n\n## License\n\n[Apache License 2.0](https://github.com/lukasalexanderweber/lir/blob/main/LICENSE)\n\n## Acknowledgements\n\nThanks to [Tim Swan](https://www.linkedin.com/in/tim-swan-14b1b/) for making\nhis Largest Interior Rectangle implementation in C# [open source](https://github.com/Evryway/lir)\nand did a great [blog post](https://www.evryway.com/largest-interior/) about it.\nThe first part was mainly reimplementing his solution in Python.\n\nThe used Algorithm was described 2019 in\n[Algorithm for finding the largest inscribed rectangle in polygon](https://journals.ut.ac.ir/article_71280_2a21de484e568a9e396458a5930ca06a.pdf)\nby [Zahraa Marzeh, Maryam Tahmasbi and Narges Mireh](https://journals.ut.ac.ir/article_71280.html).\n\nThanks also to [Mark Setchell](https://stackoverflow.com/users/2836621/mark-setchell)\nand [joni](https://stackoverflow.com/users/4745529/joni) who greatly helped\noptimizing the performance using cpython/numba in [this SO querstion](https://stackoverflow.com/questions/69854335/optimize-the-calculation-of-horizontal-and-vertical-adjacency-using-numpy)\n\n## How it works\n\nFor a binary grid:\n\n![grid](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/cells.png?raw=true)\n\nWe can specify for each cell how far one can go to the right and to the bottom:\n\nHorizontal Adjacency             |  Vertical Adjacency\n:-------------------------:|:-------------------------:\n![h_adjacency](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/h_adjacency.png?raw=true) | ![v_adjacency](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/v_adjacency.png?raw=true)\n\nNow the goal is to find the possible rectangles for each cell.\nFor that, we can specify a Horizontal Vector based on the Horizontal\nAdjacency and Vertical Vector based on the Vertical Adjacency:\n\nHorizontal Vector (2,2)             |  Vertical Vector (2,2)\n:-------------------------:|:-------------------------:\n![h_vector](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/h_vector.png?raw=true) | ![h_vector](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/v_vector.png?raw=true)\n\nSo at the given cell (2,2) the Horizontal Vector is (5,4) and\nthe Vertical Vector is (7,4).\n\nReversing either vector lets you create the spans by stacking the vectors,\nso for example reversing the Vertical Vector to (4,7) gives a set of spans\nof (5 by 4) and (4 by 7).\n\nSince `4*7=28 \u003e 5*4=20` a rectangle with width 4 and height 7 is the biggest\npossible rectangle for cell (2,2). The width and height is stored in a\nspan map, where the widths and heights of the maximum rectangles are\nstored for all cells. Using the area we can identify the biggest rectangle at\n(2, 2) with width 4 and height 7.\n\nWidths             |  Heights             |  Areas\n:-------------------------:|:-------------------------:|:-------------------------:\n![span_map_widths](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/span_map_widths.png?raw=true) | ![span_map_heights](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/span_map_heights.png?raw=true) | ![span_map_areas](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/span_map_areas.png?raw=true)\n\n------------\n\n## LIR based on contour\n\nEspecially for bigger grids the functionality can be further optimized by\nonly analysing the outline of a polygon. Here are timings created by\ncalculating the lir for [masks in different resolutions](https://github.com/lukasalexanderweber/lir/tree/main/ext/performance_comparison):\n\nTimings             |  Timings (log transformed)\n:-------------------------:|:-------------------------:\n![performance_comparison](https://github.com/lukasalexanderweber/lir/blob/main/ext/performance_comparison/performance_comparison.png?raw=true) | ![performance_comparison_log](https://github.com/lukasalexanderweber/lir/blob/main/ext/performance_comparison/performance_comparison_log.png?raw=true)\n\nThe computation costs are saved by analysing only the contour pixels instead\nof all cells. We utilize the fact that the LIR always touches the outline\nof the polygon. Here is how it works:\n\n![grid](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/cells2.png?raw=true)\n\nAn outline cell can span into one (blue), two (green) or three (red)\ndirections (up, down, left, right):\n\n![direction_map](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/direction_map.png?raw=true)\n\nBy calculating the spans in all possible directions we can obtain a span map:\n\nWidths             |  Heights             |  Areas\n:-------------------------:|:-------------------------:|:-------------------------:\n![span_map_widths](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/span_map_widths.png?raw=true) | ![span_map_heights](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/span_map_heights.png?raw=true) | ![span_map_areas](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/span_map_areas.png?raw=true)\n\nTo analyse what happens here we'll have a closer look at cell (4,2).\n\n![direction_map_cell_2_2](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/direction_map_cell_2_2.png?raw=true)\n\nIt can span into 3 directions: left, down and right. Going to left and down\nthe maximum span is (3 by 7). The final spans are noted in left2right and\ntop2bottom notation. In this case, however, the width is calculated from\nright2left. We can transform it with the simple formula\n`x = cell_x - span_width + 1`, in this case `4 - 3 + 1 = 2`.\nSince the height is already calculated from top2bottom y doesn't change\nand the span (3 by 7) is allocated to cell (2,2) (black dotted).\n\n(2,2) is (besides (1,6)) the cell with the biggest area in the span map.\nHowever, the information that the rectangle can be expanded to the right\n(turquoise dotted) is missing.\n\nSo for \"candidate cells\" like (2,2) which do not lie on the outline and\ncome from outline cells going in 3 directions, we create a new span map\n(using left2right and top2bottom adjacencies):\n\n![candidate_map](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/candidate_map.png?raw=true)\n\nWidths             |  Heights             |  Areas\n:-------------------------:|:-------------------------:|:-------------------------:\n![span_map2_widths](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/span_map2_widths.png?raw=true) | ![span_map2_heights](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/span_map2_heights.png?raw=true) | ![span_map2_areas](https://github.com/lukasalexanderweber/lir/blob/main/ext/readme_imgs/outline_approach/span_map2_areas.png?raw=true)\n\nThe biggest span of the two span maps are compared and the bigger one\nreturned as lir, in this case cell (2,2) with a span (4 by 7)\n","funding_links":["https://opencollective.com/openstitching"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenstitching%2Flir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenstitching%2Flir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenstitching%2Flir/lists"}