From ca8454ed8c29cee167df3e6bdad14d13f2cdefe6 Mon Sep 17 00:00:00 2001 From: Alexey Trekin Date: Fri, 24 Apr 2020 09:32:11 +0300 Subject: [PATCH 1/4] Add 'approx' parameter to polygonize(), default value is previous hard-coded value. If we want less approximation, now we can specify approx=cv2.APPROX_SIMPLE and epsilon=0.0. --- aeronet/dataset/transforms/_vectorize.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/aeronet/dataset/transforms/_vectorize.py b/aeronet/dataset/transforms/_vectorize.py index c01fb61..aeb0aeb 100644 --- a/aeronet/dataset/transforms/_vectorize.py +++ b/aeronet/dataset/transforms/_vectorize.py @@ -7,7 +7,7 @@ from ..vector import Feature, FeatureCollection -def polygonize(sample, epsilon=0.1, properties={}): +def polygonize(sample, epsilon=0.1, approx=cv2.CHAIN_APPROX_TC89_KCOS, properties={}): """ TODO: fill Args: sample: @@ -15,7 +15,7 @@ def polygonize(sample, epsilon=0.1, properties={}): Returns: FeatureCollection """ - geoms = _vectorize(sample.numpy(), epsilon=epsilon, transform=sample.transform) + geoms = _vectorize(sample.numpy(), epsilon=epsilon, approx=approx, transform=sample.transform) # remove all the geometries except for polygons polys = _extract_polygons(geoms) features = ([Feature(geometry, properties=properties, crs=sample.crs) @@ -46,7 +46,10 @@ def _extract_polygons(geometries): shapes += sh return shapes -def _vectorize(binary_image, epsilon=0., min_area=1., transform=IDENTITY, upscale=1): + +def _vectorize(binary_image, + epsilon=0., min_area=1., approx=cv2.CHAIN_APPROX_TC89_KCOS, + transform=IDENTITY, upscale=1): """ Vectorize binary image, returns a 4-level list of floats [[[[X,Y]]]] @@ -71,7 +74,7 @@ def _vectorize(binary_image, epsilon=0., min_area=1., transform=IDENTITY, upscal # search for all contours contours_result = cv2.findContours( binary_image, - cv2.RETR_CCOMP, cv2.CHAIN_APPROX_TC89_KCOS) + cv2.RETR_CCOMP, approx) # For compatibility with opencv3, where contours_result[0]=image, so we should throw it away contours, hierarchy = contours_result if len(contours_result) == 2 else contours_result[1:] From c697d0e5b5737a6b318f6e82f952cfec5c463ce2 Mon Sep 17 00:00:00 2001 From: Alexey Trekin Date: Fri, 24 Apr 2020 09:39:23 +0300 Subject: [PATCH 2/4] Add 'approx' parameter to polygonize(), default value is previous hard-coded value. If we want less approximation, now we can specify approx=cv2.APPROX_SIMPLE and epsilon=0.0. Merged with master --- aeronet/dataset/transforms/_vectorize.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aeronet/dataset/transforms/_vectorize.py b/aeronet/dataset/transforms/_vectorize.py index 6014ae6..ecbc45c 100644 --- a/aeronet/dataset/transforms/_vectorize.py +++ b/aeronet/dataset/transforms/_vectorize.py @@ -25,10 +25,11 @@ def polygonize(sample, epsilon=0.1, approx=cv2.CHAIN_APPROX_TC89_KCOS, propertie epsilon: the epsilon parameter for the cv2.approxPolyDP, which specifies the approximation accuracy. This is the maximum distance between the original curve and its approximation properties: (dict) Properties to be added to the resulting FeatureCollection - + approx: Approximation parameter for cv2:findContours Returns: FeatureCollection: Polygons in the CRS of the sample, that represent non-black objects in the image + """ geoms = _vectorize(sample.numpy(), epsilon=epsilon, approx=approx, transform=sample.transform) # remove all the geometries except for polygons From 96f16b5e6e35dbb09a43ac6497d78fa217b4d235 Mon Sep 17 00:00:00 2001 From: Alexey Trekin Date: Mon, 15 Jun 2020 11:28:22 +0300 Subject: [PATCH 3/4] Return upscale pareameter to polygonize (upscale raster mask before vectorization) --- aeronet/dataset/transforms/_vectorize.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aeronet/dataset/transforms/_vectorize.py b/aeronet/dataset/transforms/_vectorize.py index ecbc45c..3d9053d 100644 --- a/aeronet/dataset/transforms/_vectorize.py +++ b/aeronet/dataset/transforms/_vectorize.py @@ -7,7 +7,7 @@ from ..vector import Feature, FeatureCollection -def polygonize(sample, epsilon=0.1, approx=cv2.CHAIN_APPROX_TC89_KCOS, properties={}): +def polygonize(sample, epsilon=0.1, properties={}, approx=cv2.CHAIN_APPROX_TC89_KCOS, upscale=1.0): """ Transform the raster mask to vector polygons. The pixels in the raster mask are treated as belonging to the object if their value is non-zero, and zero values are background. All the objects are transformed to the vector form (polygons). @@ -26,6 +26,9 @@ def polygonize(sample, epsilon=0.1, approx=cv2.CHAIN_APPROX_TC89_KCOS, propertie This is the maximum distance between the original curve and its approximation properties: (dict) Properties to be added to the resulting FeatureCollection approx: Approximation parameter for cv2:findContours + upscale (float): scale image for better precision of the polygon. The polygon is correctly downscaled back. + works only when `upscale > 1`, default value means no upscaling + Returns: FeatureCollection: Polygons in the CRS of the sample, that represent non-black objects in the image @@ -38,6 +41,7 @@ def polygonize(sample, epsilon=0.1, approx=cv2.CHAIN_APPROX_TC89_KCOS, propertie for geometry in polys]) return FeatureCollection(features, crs=sample.crs) + def _extract_polygons(geometries): """ Makes the consistent polygon-only geometry list of valid polygons @@ -65,7 +69,7 @@ def _extract_polygons(geometries): def _vectorize(binary_image, epsilon=0., min_area=1., approx=cv2.CHAIN_APPROX_TC89_KCOS, - transform=IDENTITY, upscale=1): + transform=IDENTITY, upscale=1.0): """ Vectorize binary image, returns a 4-level list of floats [[[[X,Y]]]] From f23c0683388d7cec69b87a894597fdec9c7f8131 Mon Sep 17 00:00:00 2001 From: Alexey Trekin Date: Mon, 15 Jun 2020 12:28:27 +0300 Subject: [PATCH 4/4] Replace cv2-based approx parameter to string representation, removed default mutable properties param --- aeronet/dataset/transforms/_vectorize.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/aeronet/dataset/transforms/_vectorize.py b/aeronet/dataset/transforms/_vectorize.py index 3d9053d..ff7ece3 100644 --- a/aeronet/dataset/transforms/_vectorize.py +++ b/aeronet/dataset/transforms/_vectorize.py @@ -6,8 +6,12 @@ from ..vector import Feature, FeatureCollection +cv_approx = {'simple': cv2.CHAIN_APPROX_SIMPLE, + 'tc89_kcos': cv2.CHAIN_APPROX_TC89_KCOS, + 'tc89_l1': cv2.CHAIN_APPROX_TC89_L1} -def polygonize(sample, epsilon=0.1, properties={}, approx=cv2.CHAIN_APPROX_TC89_KCOS, upscale=1.0): + +def polygonize(sample, epsilon=0.1, properties=None, approx='tc89_kcos', upscale=1.0): """ Transform the raster mask to vector polygons. The pixels in the raster mask are treated as belonging to the object if their value is non-zero, and zero values are background. All the objects are transformed to the vector form (polygons). @@ -34,9 +38,14 @@ def polygonize(sample, epsilon=0.1, properties={}, approx=cv2.CHAIN_APPROX_TC89_ Polygons in the CRS of the sample, that represent non-black objects in the image """ + + approx = cv_approx[approx.lower()] geoms = _vectorize(sample.numpy(), epsilon=epsilon, approx=approx, transform=sample.transform) # remove all the geometries except for polygons polys = _extract_polygons(geoms) + + if properties is None: + properties = {} features = ([Feature(geometry, properties=properties, crs=sample.crs) for geometry in polys]) return FeatureCollection(features, crs=sample.crs)