Skip to content

API Reference

vector_utilities

VectorDataset(path)

Source code in apb_spatial_computer_vision/vector_utilities.py
82
83
84
85
86
87
88
89
def __init__(self,path):
    self.vector_path=path
    extension=os.path.splitext(path)[1]
    self.driver=ogr.GetDriverByName(driverDict[extension])
    self.dataset=self.driver.Open(self.vector_path)
    self.layer=self.dataset.GetLayer()
    self.crs=self._get_crs()
    pass

regularize_circles_file(file, output=None, threshold=0.01, file_gpkg_layer=None)

Recovers a circular geometry as

Parameters:

Name Type Description Default
file _type_

description

required
output str

description. Defaults to None.

None
threshold float

description. Defaults to 0.01.

0.01
file_gpkg_layer _type_

description. Defaults to None.

None

Raises:

Type Description
Exception

description

Exception

description

Returns:

Name Type Description
_type_

description

Source code in apb_spatial_computer_vision/vector_utilities.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
def regularize_circles_file(file,output:str=None,threshold: float = 0.01,file_gpkg_layer=None):
    """Recovers a circular geometry as 

    Args:
        file (_type_): _description_
        output (str, optional): _description_. Defaults to None.
        threshold (float, optional): _description_. Defaults to 0.01.
        file_gpkg_layer (_type_, optional): _description_. Defaults to None.

    Raises:
        Exception: _description_
        Exception: _description_

    Returns:
        _type_: _description_
    """

    if isinstance(file,str):
        if os.path.exists(file):
            if file_gpkg_layer is not None:
                gdf=gpd.read_file(file,layer=file_gpkg_layer)
            else:
                gdf=gpd.read_file(file)
        else:
            raise Exception('Path does not exist')

    elif isinstance(file,gpd.GeoDataFrame):
        gdf=file.copy()

    else:
        raise Exception('Only valid paths recognized by GeoPandas or GeoDataFrames accepted')

    convex_hull=gdf.geometry.convex_hull
    polygons=gpd.GeoDataFrame([regress_circle(polygon,threshold) for polygon in convex_hull],
                              columns=['geom','std','regressed'],
                              geometry='geom',crs=gdf.crs)
    #polygons['regressed']=polygons['std']<sqrt(threshold)

    if output is not None:
        extension=os.path.splitext(output)[1]
        if extension=='':
            extension='.parquet'
            output+=extension
        if extension=='.parquet':
            polygons.to_parquet(output)
        else:
            polygons.to_file(output)
    else:
        return polygons

regress_circle(polygon, threshold=0.001)

Regresses approximately circular geometries into the least-squares best fit circle using Levenberg-Marquardt algorithm (MINIPACK)

Parameters:

Name Type Description Default
polygon Polygon

Polygon to be regressed

required
threshold float

description. Defaults to 0.001.

0.001

Returns:

Type Description

shapely.Polygon: Polygon with an edge length equal to the threshold and a circular shape based on the least squares-regressed equation.

Source code in apb_spatial_computer_vision/vector_utilities.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def regress_circle(polygon:shapely.Polygon,threshold=0.001):
    """Regresses approximately circular geometries into the least-squares best fit circle using Levenberg-Marquardt algorithm (MINIPACK)

    Args:
        polygon (shapely.Polygon): Polygon to be regressed
        threshold (float, optional): _description_. Defaults to 0.001.

    Returns:
        shapely.Polygon: Polygon with an edge length equal to the threshold and a circular shape based on the least squares-regressed equation.
    """

    pred_center=polygon.centroid
    np_exterior=np.array(polygon.boundary.coords)
    # if len(np_exterior)==4:
    #     return polygon

    x=np_exterior[:,0]
    y=np_exterior[:,1]

    f=least_squares(circle,x0=[pred_center.x,pred_center.y,10],args=(x,y),method='lm')

    a,b,r=float(f.x[0]),float(f.x[1]),float(f.x[2])
    v=np.transpose(np.array([(x-np.full_like(x,a))**2+(y-np.full_like(x,b))**2-np.full_like(a,r**2)]))
    std=sqrt(float(np.matmul(np.transpose(v),v))/(v.shape[0]-len(f.x)))
    #/(v.shape[0]-len(f.x)))
    #print(std, v.shape[0])
    if std>sqrt(threshold)*r**2:
        #print(f'{counter,v.shape[0]}')
        return polygon,std,False

    angles=np.linspace(0,2*pi,int(2*pi/asin(threshold/r)+1))

    x=np.full_like(angles,a)+np.sin(angles)*np.full_like(angles,r)
    y=np.full_like(angles,b)+np.cos(angles)*np.full_like(angles,r)
    puntos_2=np.column_stack((x,y))
    polygon=shapely.Polygon(puntos_2)
    return polygon,std,True