{"id":911,"date":"2022-08-15T08:00:51","date_gmt":"2022-08-15T08:00:51","guid":{"rendered":"https:\/\/ml-gis-service.com\/?p=911"},"modified":"2022-08-15T08:00:52","modified_gmt":"2022-08-15T08:00:52","slug":"toolbox-get-bounding-box-polygon-and-centroid-of-a-point-cloud-in-python","status":"publish","type":"post","link":"https:\/\/ml-gis-service.com\/index.php\/2022\/08\/15\/toolbox-get-bounding-box-polygon-and-centroid-of-a-point-cloud-in-python\/","title":{"rendered":"Toolbox: Get Bounding Box Polygon and centroid of a point cloud in Python"},"content":{"rendered":"\n<p>Let&#8217;s assume that we have a set of points, for example:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"547\" height=\"604\" src=\"https:\/\/ml-gis-service.com\/wp-content\/uploads\/2022\/08\/centroids.png\" alt=\"\" class=\"wp-image-912\" srcset=\"https:\/\/ml-gis-service.com\/wp-content\/uploads\/2022\/08\/centroids.png 547w, https:\/\/ml-gis-service.com\/wp-content\/uploads\/2022\/08\/centroids-272x300.png 272w\" sizes=\"auto, (max-width: 547px) 100vw, 547px\" \/><\/figure><\/div>\n\n\n<p>And we would like to get their <strong>Bounding Box<\/strong> and its <strong>centroid<\/strong>. How do we achieve it? We can use <code>shapely<\/code> and <code>GeoPandas<\/code> packages for it!<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from typing import Union\n\nimport geopandas as gpd\nfrom shapely.geometry import Polygon\n\n\ndef points_to_bounding_box(points: Union[gpd.GeoSeries, gpd.GeoDataFrame]):\n    \"\"\"\n    Function transform a set of points into a Polygon with bounding box.\n    \n    Parameters\n    ----------\n    points : gpd.GeoSeries\n    \n    Returns\n    -------\n    bounding_box : Polygon\n    \"\"\"\n    bounds = points.total_bounds\n    \n    x_min, y_min, x_max, y_max = bounds\n    \n    polygon_tuples = [\n        (x_min, y_min), (x_max, y_min), (x_max, y_max), (x_min, y_max)\n    ]\n    \n    polygon = Polygon(polygon_tuples)\n    return polygon\n\n\npoly = points_to_bounding_box(centroids)\nprint(poly)<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">POLYGON ((1305267.3457557156 210560.55098878054, 2198938.029283345 210560.55098878054, 2198938.029283345 1163583.8925663661, 1305267.3457557156 1163583.8925663661, 1305267.3457557156 210560.55098878054))<\/pre>\n\n\n\n<p>If we want to get a centroid, then we can use the <code>centroid<\/code> attribute of <code>Polygon<\/code> structure:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">print(poly.centroid)<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">POINT (1752102.6875195305 687072.2217775733)<\/pre>\n\n\n\n<p>Plotting all together can be a little bit tricky &#8211; we must change simple geometries into <code>GeoSeries<\/code> objects, and then we can plot our output:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">bb = gpd.GeoSeries(poly)\nbb.set_crs(crs=centroids.crs)  # Here we must set CRS of our baseline set of points!\n\ncent = bb.centroid  # We can generate centroid from GeoPandas GeoSeries object\n\n# Plot\n\nbase = bb.plot(color='white', edgecolor='gray', figsize=(12, 10))\ncentroids.plot(ax=base, marker='o', color='red', markersize=10);\ncent.plot(ax=base, marker='x', color='green', markersize=20)\nplt.show()<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"547\" height=\"599\" src=\"https:\/\/ml-gis-service.com\/wp-content\/uploads\/2022\/08\/bb_cent_cloud.png\" alt=\"\" class=\"wp-image-913\" srcset=\"https:\/\/ml-gis-service.com\/wp-content\/uploads\/2022\/08\/bb_cent_cloud.png 547w, https:\/\/ml-gis-service.com\/wp-content\/uploads\/2022\/08\/bb_cent_cloud-274x300.png 274w\" sizes=\"auto, (max-width: 547px) 100vw, 547px\" \/><figcaption>Point cloud (red dots), bounding box (gray rectangle within the plot), and its centroid (green x) &#8211; all generated with GeoPandas and Shapely.<\/figcaption><\/figure><\/div>","protected":false},"excerpt":{"rendered":"<p>How to get bounding box and centroid of a point cloud in Python<\/p>\n","protected":false},"author":1,"featured_media":914,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,137,3,17],"tags":[218,219,57,217,216,7,220,63,62],"class_list":["post-911","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-engineering","category-data-visualization","category-python","category-scripts","tag-bounding-box","tag-centroid","tag-geopandas","tag-get-bounding-box-of-a-point-cloud","tag-get-centroid-from-a-point-cloud","tag-python","tag-rectangle","tag-shapely","tag-spatial"],"_links":{"self":[{"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/posts\/911","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/comments?post=911"}],"version-history":[{"count":1,"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/posts\/911\/revisions"}],"predecessor-version":[{"id":915,"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/posts\/911\/revisions\/915"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/media\/914"}],"wp:attachment":[{"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/media?parent=911"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/categories?post=911"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ml-gis-service.com\/index.php\/wp-json\/wp\/v2\/tags?post=911"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}