Skip to content

Commit 3433fe4

Browse files
committed
pnts
1 parent e2855e7 commit 3433fe4

File tree

2 files changed

+104
-247
lines changed

2 files changed

+104
-247
lines changed

geospatial_learn/learning.py

Lines changed: 104 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151

5252
import pandas as pd
5353
import simpledbf
54+
from plyfile import PlyData
55+
from pyntcloud import PyntCloud
56+
import open3d as o3d
5457

5558

5659
gdal.UseExceptions()
@@ -1439,140 +1442,121 @@ def get_training(inShape, inRas, bands, field, outFile = None):
14391442

14401443
return outData, rejects
14411444

1445+
def ply_features(incld, outcld=None):
14421446

1443-
def get_training_point(inShape, inRas, bands, field):
1444-
""" Collect training as a np array for use with create model function using
1445-
point data
1446-
1447-
Parameters
1448-
--------------
1449-
1450-
inShape : string
1451-
the input shapefile - must be esri .shp at present
1452-
1453-
inRas : string
1454-
the input raster from which the training is extracted
1455-
1456-
bands : int
1457-
no of bands
1458-
1459-
field : string
1460-
the attribute field containing the training labels
1447+
"""
1448+
Calculate point cloud features and write to file
14611449
1462-
outFile : string (optional)
1463-
path to the training file saved as joblib format (eg - 'training.gz')
14641450
1465-
Returns
1466-
---------------------
1451+
Parameters
1452+
-----------
14671453
1468-
A tuple containing:
1469-
-np array of training data
1470-
-list of polygons with invalid geometry that were not collected
1454+
incld: string
1455+
the input point cloud
1456+
1457+
outcld: string
1458+
the output point cloud
1459+
14711460
1461+
"""
14721462

1473-
UNFINISHED DO NOT USE
1474-
1463+
pcd = PyntCloud.from_file(incld)
1464+
#o3d.io.read_point_cloud(incld)
1465+
1466+
#pcd.estimate_normals()
14751467

1476-
"""
1477-
#t0 = time()
1478-
outData = list()
1479-
print('Loading & prepping data')
1480-
raster = gdal.Open(inRas)
1481-
shp = ogr.Open(inShape)
1482-
lyr = shp.GetLayer()
1483-
labels = np.arange(lyr.GetFeatureCount())
1484-
rb = raster.GetRasterBand(1)
1485-
rgt = raster.GetGeoTransform()
1486-
mem_drv = ogr.GetDriverByName('Memory')
1487-
driver = gdal.GetDriverByName('MEM')
1488-
rejects = []
1468+
#cloud = PyntCloud.from_instance("open3d",
1469+
1470+
1471+
pProps =['anisotropy', "curvature", "eigenentropy", "eigen_sum", "linearity",
1472+
"omnivariance", "planarity", "sphericity"]#, "inclination_deg",
1473+
# "inclination_rad", "orientation_deg", "orientation_rad"]
1474+
#, "HueSaturationValue",#"RelativeLuminance"," RGBIntensity"]
1475+
1476+
k_neighbors = pcd.get_neighbors(k=30)
1477+
eigenvalues = pcd.add_scalar_field("eigen_values", k_neighbors=k_neighbors)
1478+
1479+
[pcd.add_scalar_field(p, ev=eigenvalues) for p in pProps]
14891480

1490-
print('getting points')
1491-
for label in tqdm(labels):
1492-
#print(label)
1493-
feat = lyr.GetFeature(label)
1494-
if feat == None:
1495-
print('no geometry for feature '+str(label))
1496-
continue
1497-
iD = feat.GetField(field)
1498-
geom = feat.GetGeometryRef()
1499-
mx,my=geom.GetX(), geom.GetY() #coord in map units
1481+
if outcld == None:
1482+
pcd.to_file(incld)
1483+
else:
1484+
pcd.to_file(outcld)
15001485

1501-
#Convert from map to pixel coordinates.
1502-
#Only works for geotransforms with no rotation.
1503-
px = int((mx - gt[0]) / gt[1]) #x pixel
1504-
py = int((my - gt[3]) / gt[5]) #y pixel
1486+
def get_training_ply(incld, label_field="scalar_label", outFile=None):
15051487

1506-
structval=rb.ReadRaster(px, py,1,1,buf_type=gdal.GDT_UInt16) #Assumes 16 bit int aka 'short'
1507-
intval = struct.unpack('h' , structval) #use the 'short' format code (2 bytes) not int (4 bytes)
1488+
"""
1489+
Get training from a point cloud
15081490
1509-
print(intval[0])
1510-
# Get raster georeference info
1511-
1512-
# src_offset = bbox_to_pixel_offsets(rgt, geom)
1513-
#
1514-
#
1515-
# # calculate new geotransform of the feature subset
1516-
# new_gt = (
1517-
# (rgt[0] + (src_offset[0] * rgt[1])),
1518-
# rgt[1],
1519-
# 0.0,
1520-
# (rgt[3] + (src_offset[1] * rgt[5])),
1521-
# 0.0,
1522-
# rgt[5])
1523-
1524-
1525-
# Create a temporary vector layer in memory
1526-
mem_ds = mem_drv.CreateDataSource('out')
1527-
mem_layer = mem_ds.CreateLayer('poly', None, ogr.wkbPolygon)
1528-
mem_layer.CreateFeature(feat.Clone())
1529-
1530-
# Rasterize it
1531-
rvds = driver.Create('', src_offset[2], src_offset[3], 1, gdal.GDT_Byte)
1532-
rvds.SetGeoTransform(new_gt)
1533-
gdal.RasterizeLayer(rvds, [1], mem_layer, burn_values=[1])
1534-
rv_array = rvds.ReadAsArray()
1535-
1536-
# Mask the source data array with our current feature
1537-
# we take the logical_not to flip 0<->1 to get the correct mask effect
1538-
# we also mask out nodata values explictly
1539-
1491+
1492+
Parameters
1493+
-----------
1494+
1495+
incld: string
1496+
the input point cloud
1497+
1498+
label_field: string
1499+
the name of the field representing the training points which must
1500+
be positive integers
1501+
1502+
outFile: string
1503+
path to training array to be saved as .gz via joblib
1504+
15401505
1506+
"""
1507+
# TODO Clean up lack of loops funcs to do stuff
1508+
# classify ply TODO also
1509+
# convert Open3D.o3d.geometry to necessary vars
1510+
pcd = o3d.io.read_point_cloud(incld)
1511+
xyz = np.asarray(pcd.points)
1512+
cols = np.asarray(pcd.colors)
1513+
norms = np.asarray(pcd.normals)
1514+
pf = PlyData.read(incld)
1515+
1516+
# pProps =['anisotropy', 'curvature', "eigenentropy", "eigen_sum",
1517+
# "linearity", "omnivariance", "planarity", "sphericity"]
1518+
1519+
# doesn't matter if this is a float
1520+
label = np.array(pf.elements[0].data['scalar_label'], dtype='float64')
1521+
a = np.array(pf.elements[0].data['anisotropy(26)'], dtype='float64')
1522+
c = np.array(pf.elements[0].data["curvature(26)"], dtype='float64')
1523+
et = np.array(pf.elements[0].data["eigenentropy(26)"], dtype='float64')
1524+
es = np.array(pf.elements[0].data["eigen_sum(26)"], dtype='float64')
1525+
l = np.array(pf.elements[0].data["linearity(26)"], dtype='float64')
1526+
om = np.array(pf.elements[0].data["linearity(26)"], dtype='float64')
1527+
pl = np.array(pf.elements[0].data["omnivariance(26)"], dtype='float64')
1528+
sp = np.array(pf.elements[0].data["sphericity(26)"], dtype='float64')
1529+
1530+
label.shape = (label.shape[0], 1)
1531+
a.shape=(label.shape[0], 1)
1532+
c.shape=(label.shape[0], 1)
1533+
et.shape=(label.shape[0], 1)
1534+
es.shape=(label.shape[0], 1)
1535+
l.shape=(label.shape[0], 1)
1536+
om.shape=(label.shape[0], 1)
1537+
pl.shape=(label.shape[0], 1)
1538+
sp.shape=(label.shape[0], 1)
1539+
1540+
final = np.hstack((label, xyz, cols, norms, a, c, et, es, l, om, pl, sp))
1541+
1542+
# all these could be dumped now
1543+
del xyz, cols, norms, pf, a, c, et, es, l, om, pl, sp
1544+
1545+
# prep for sklearn
1546+
X_train = final[final[:,0] >= 0]
15411547

1542-
1543-
rb = raster.GetRasterBand(1)
1544-
src_array = rb.ReadAsArray(src_offset[0], src_offset[1], src_offset[2],
1545-
src_offset[3])
1546-
if np.shape(src_array) is ():
1547-
rejects.append(label)
1548-
continue
1549-
# Read raster as arrays
1550-
for band in range(1,bands+1):
1551-
1552-
rb = raster.GetRasterBand(band)
1553-
src_array = rb.ReadAsArray(src_offset[0], src_offset[1], src_offset[2],
1554-
src_offset[3])
1555-
if src_array is None:
1556-
src_array = rb.ReadAsArray(src_offset[0]-1, src_offset[1], src_offset[2],
1557-
src_offset[3])
1558-
1559-
masked = np.ma.MaskedArray(src_array,
1560-
mask=np.logical_or(src_array == 0,
1561-
np.logical_not(rv_array)))
1562-
1563-
1564-
datafinal = masked.flatten()
1548+
# Remove non-finite values
1549+
X_train = X_train[np.isfinite(X_train).all(axis=1)]
1550+
1551+
# y labels
1552+
#y_train = X_train[:,0]
1553+
1554+
if outFile != None:
1555+
jb.dump(X_train, outFile, compress=2)
1556+
1557+
return X_train
1558+
15651559

1566-
if band == 1:
1567-
X = np.zeros(shape = (datafinal.shape[0], bands+1))
1568-
X[:,0] = iD
1569-
1570-
X[:,band] = datafinal
1571-
#print(label,fieldval,xcount, ycount)
1572-
outData.append(X)
1573-
outData = np.asarray(outData)
1574-
outData = np.concatenate(outData).astype(None)
1575-
return outData, rejects
15761560

15771561

15781562
def rmse_vector_lyr(inShape, attributes):

geospatial_learn/utilities.py

Lines changed: 0 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,133 +1893,6 @@ def rotate_im(image, angle):
18931893
return image
18941894

18951895

1896-
def get_corners(bboxes):
1897-
1898-
"""Get corners of bounding boxes
1899-
1900-
Parameters
1901-
----------
1902-
1903-
bboxes: numpy.ndarray
1904-
Numpy array containing bounding boxes of shape `N X 4` where N is the
1905-
number of bounding boxes and the bounding boxes are represented in the
1906-
format `x1 y1 x2 y2`
1907-
1908-
returns
1909-
-------
1910-
1911-
numpy.ndarray
1912-
Numpy array of shape `N x 8` containing N bounding boxes each described by their
1913-
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
1914-
1915-
"""
1916-
width = (bboxes[:,2] - bboxes[:,0]).reshape(-1,1)
1917-
height = (bboxes[:,3] - bboxes[:,1]).reshape(-1,1)
1918-
1919-
x1 = bboxes[:,0].reshape(-1,1)
1920-
y1 = bboxes[:,1].reshape(-1,1)
1921-
1922-
x2 = x1 + width
1923-
y2 = y1
1924-
1925-
x3 = x1
1926-
y3 = y1 + height
1927-
1928-
x4 = bboxes[:,2].reshape(-1,1)
1929-
y4 = bboxes[:,3].reshape(-1,1)
1930-
1931-
corners = np.hstack((x1,y1,x2,y2,x3,y3,x4,y4))
1932-
1933-
return corners
1934-
1935-
1936-
def rotate_box(corners,angle, cx, cy, h, w):
1937-
1938-
"""Rotate the bounding box.
1939-
1940-
1941-
Parameters
1942-
----------
1943-
1944-
corners : numpy.ndarray
1945-
Numpy array of shape `N x 8` containing N bounding boxes each described by their
1946-
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
1947-
1948-
angle : float
1949-
angle by which the image is to be rotated
1950-
1951-
cx : int
1952-
x coordinate of the center of image (about which the box will be rotated)
1953-
1954-
cy : int
1955-
y coordinate of the center of image (about which the box will be rotated)
1956-
1957-
h : int
1958-
height of the image
1959-
1960-
w : int
1961-
width of the image
1962-
1963-
Returns
1964-
-------
1965-
1966-
numpy.ndarray
1967-
Numpy array of shape `N x 8` containing N rotated bounding boxes each described by their
1968-
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
1969-
"""
1970-
1971-
corners = corners.reshape(-1,2)
1972-
corners = np.hstack((corners, np.ones((corners.shape[0],1), dtype = type(corners[0][0]))))
1973-
1974-
M = cv2.getRotationMatrix2D((cx, cy), angle, 1.0)
1975-
1976-
1977-
cos = np.abs(M[0, 0])
1978-
sin = np.abs(M[0, 1])
1979-
1980-
nW = int((h * sin) + (w * cos))
1981-
nH = int((h * cos) + (w * sin))
1982-
# adjust the rotation matrix to take into account translation
1983-
M[0, 2] += (nW / 2) - cx
1984-
M[1, 2] += (nH / 2) - cy
1985-
# Prepare the vector to be transformed
1986-
calculated = np.dot(M,corners.T).T
1987-
1988-
calculated = calculated.reshape(-1,8)
1989-
1990-
return calculated
1991-
1992-
def get_enclosing_box(corners):
1993-
"""Get an enclosing box for ratated corners of a bounding box
1994-
1995-
Parameters
1996-
----------
1997-
1998-
corners : numpy.ndarray
1999-
Numpy array of shape `N x 8` containing N bounding boxes each described by their
2000-
corner co-ordinates `x1 y1 x2 y2 x3 y3 x4 y4`
2001-
2002-
Returns
2003-
-------
2004-
2005-
numpy.ndarray
2006-
Numpy array containing enclosing bounding boxes of shape `N X 4` where N is the
2007-
number of bounding boxes and the bounding boxes are represented in the
2008-
format `x1 y1 x2 y2`
2009-
2010-
"""
2011-
x_ = corners[:,[0,2,4,6]]
2012-
y_ = corners[:,[1,3,5,7]]
2013-
2014-
xmin = np.min(x_,1).reshape(-1,1)
2015-
ymin = np.min(y_,1).reshape(-1,1)
2016-
xmax = np.max(x_,1).reshape(-1,1)
2017-
ymax = np.max(y_,1).reshape(-1,1)
2018-
2019-
final = np.hstack((xmin, ymin, xmax, ymax,corners[:,8:]))
2020-
2021-
return final
2022-
20231896
def spinim(self, img, bboxes):
20241897

20251898
angle = random.uniform(*self.angle)

0 commit comments

Comments
 (0)