converting ply to postgis, script works but volume is invalid - postgis

I'm trying to convert a ply to a polyhedron stored in postgis.
In this example I have a cube from 0,0,0 to 1,1,1 the script below brings in a geometry to postgis, it is there, no problem, however I go to calculate the volume and it gives the following error:
query:
SELECT ST_Volume(st_geomfromtext) FROM public.test3
error:
ERROR: PolyhedralSurface is invalid : inconsistent orientation of PolyhedralSurface detected at edge 1 (4-3) of polygon 11 : POLYHEDRALSURFACE(((1/1 1/1 0/1,1/1 0/1 0/1,0/1 0/1 0/1,1/1 1/1 0/1)),((1/1 0/1 0/1,1/1 0/1 1/1,0/1 0/1 0/1,1/1 0/1 0/1)),((1/1 0/1 0/1,1
SQL state: XX000
The object is a cube 0,0,0 to 1,1,1, here it is as an array of vertices and triangles.
vertices:
array([[ 1., 1., -0.],
[ 1., 0., -0.],
[ 0., 0., -0.],
[ 0., 1., -0.],
[ 1., 1., 1.],
[ 0., 1., 1.],
[ 0., 0., 1.],
[ 1., 0., 1.],
[ 1., 1., -0.],
[ 1., 1., 1.],
[ 1., 0., 1.],
[ 1., 0., -0.],
[ 1., 0., -0.],
[ 1., 0., 1.],
[ 0., 0., 1.],
[ 0., 0., -0.],
[ 0., 0., -0.],
[ 0., 0., 1.],
[ 0., 1., 1.],
[ 0., 1., -0.],
[ 1., 1., 1.],
[ 1., 1., -0.],
[ 0., 1., -0.],
[ 0., 1., 1.]])
The triangles are defined as:
array([[ 0, 1, 2],
[ 0, 2, 3],
[ 4, 5, 6],
[ 4, 6, 7],
[ 8, 9, 10],
[ 8, 10, 11],
[12, 13, 14],
[12, 14, 15],
[16, 17, 18],
[16, 18, 19],
[20, 21, 22],
[20, 22, 23]], dtype=int32)
I put together this conversion script to take a ply and add it to postgis:
import numpy as np
from open3d import *
import psycopg2
import dbconfig
def connect_db():
global connection
connection = psycopg2.connect(host=dbconfig.DATABASE_CONFIG['host'],
user=dbconfig.DATABASE_CONFIG['user'],
password=dbconfig.DATABASE_CONFIG['password'],
dbname=dbconfig.DATABASE_CONFIG['dbname'])
return connection
# mesh = read_triangle_mesh('C:/Users/garyn/PycharmProjects/pointcloudprocessor/tmp/contexts/99.526/396.ply')
mesh = read_triangle_mesh('C:/Users/garyn/PycharmProjects/pointcloudprocessor/tmp/contexts/cube3.ply')
verts = mesh.vertices
verts = np.asarray(verts)
tri = mesh.triangles
tri = np.asarray(tri)
data = ''
header = ("'POLYHEDRALSURFACE(")
for i in range(len(tri)):
# for i in range(0,2):
x1 = (tri[i][0]) # 3
y1 = (tri[i][1]) # 44
z1 = (tri[i][2]) # 1
x_coords1 = verts[x1][0]
y_coords1 = verts[y1][0]
z_coords1 = verts[z1][0]
x_coords2 = verts[x1][1]
y_coords2 = verts[y1][1]
z_coords2 = verts[z1][1]
x_coords3 = verts[x1][2]
y_coords3 = verts[y1][2]
z_coords3 = verts[z1][2]
data += "((%s %s %s, %s %s %s, %s %s %s, %s %s %s))," % \
(x_coords1, y_coords1, z_coords1, \
x_coords2, y_coords2, z_coords2, \
x_coords3, y_coords3, z_coords3, \
x_coords1, y_coords1, z_coords1)
data = data[:-1]
projection = ")',32635)"
create_stmt = "CREATE TABLE test3 AS "
select_stmt = "SELECT ST_GeomFromText("
polyhedron = header + data + projection
query = create_stmt + select_stmt + polyhedron
conn = connect_db()
cur = conn.cursor()
cur.execute(query)
conn.commit()
cur.close()
conn.close()
Which results in:
CREATE TABLE test3 AS
SELECT ST_GeomFromText('POLYHEDRALSURFACE(((1.0 1.0 0.0, 1.0 0.0 0.0, -0.0 -0.0 -0.0, 1.0 1.0 0.0)),((1.0 0.0 0.0, 1.0 0.0 1.0, -0.0 -0.0 -0.0, 1.0 0.0 0.0)),((1.0 0.0 0.0, 1.0 1.0 0.0, 1.0 1.0 1.0, 1.0 0.0 0.0)),((1.0 0.0 1.0, 1.0 0.0 0.0, 1.0 1.0 1.0, 1.0 0.0 1.0)),((1.0 1.0 1.0, 1.0 1.0 0.0, -0.0 1.0 1.0, 1.0 1.0 1.0)),((1.0 1.0 1.0, 1.0 0.0 0.0, -0.0 1.0 -0.0, 1.0 1.0 1.0)),((1.0 1.0 0.0, 0.0 0.0 0.0, -0.0 1.0 1.0, 1.0 1.0 0.0)),((1.0 0.0 0.0, 0.0 0.0 0.0, -0.0 1.0 -0.0, 1.0 0.0 0.0)),((0.0 0.0 0.0, 0.0 0.0 1.0, -0.0 1.0 1.0, 0.0 0.0 0.0)),((0.0 0.0 0.0, 0.0 1.0 1.0, -0.0 1.0 -0.0, 0.0 0.0 0.0)),((1.0 1.0 0.0, 1.0 1.0 1.0, 1.0 -0.0 -0.0, 1.0 1.0 0.0)),((1.0 0.0 0.0, 1.0 1.0 1.0, 1.0 -0.0 1.0, 1.0 0.0 0.0)))',32635)
It looks ok to me and postgis accepts it as a polyhedral surface, but how do I make sure the cube is constructed correctly? P.S. and postgis 3D viewers out there, I'm doing this blind.

I solved it, I had the ordering wrong, here is the correct ordering.
data = ''
header = ("'POLYHEDRALSURFACE(")
for i in range(len(tri)):
# for i in range(0,2):
x1 = (tri[i][0]) # 3
y1 = (tri[i][1]) # 44
z1 = (tri[i][2]) # 1
coords1 = verts[x1][0]
coords2 = verts[x1][1]
coords3 = verts[x1][2]
coords4 = verts[y1][0]
coords5 = verts[y1][1]
coords6 = verts[y1][2]
coords7 = verts[z1][0]
coords8 = verts[z1][1]
coords9 = verts[z1][2]
data += "((%s %s %s, %s %s %s, %s %s %s, %s %s %s))," % \
(
coords1, coords2, coords3,
coords4, coords5, coords6,
coords7, coords8, coords9,
coords1, coords2, coords3
)
data = data[:-1]

Related

cv.fillPoly generating zero arrays, not reading inputs

I have
blank = np.zeros(shape = im.shape, dtype = np.float32)
which generates
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
I have [label2poly[label]] which is dtype('int32')
[array([[ 716, 1],
[ 710, 281],
[ 727, 322],
[ 756, 369],
[ 793, 399],
[ 863, 406],
[ 952, 416],
[ 978, 412],
[ 416, 1]])]
When I try cv2.fillPoly(blank, [label2poly[label]], 255) it outputs
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]], dtype=float32)`
where it should have been something like
array([[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 255., ..., 0., 0., 0.],
[ 0., 0., 255., ..., 0., 0., 0.],
...,
[ 0., 255., 255., ..., 255., 255., 255.],
[ 0., 255., 255., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
I am trying to create multiple masks. Would appreciate any help.
Initialization of blank:
blank = np.zeros(shape=[5, 5], dtype=np.float32)
print(blank)
Output:
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
Initialization of label followed by a call to fillPoly() which uses is as a mask to fill blank with 255 at specific positions:
label = np.array([[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]], dtype=np.int32)
cv2.fillPoly(blank, [label], 255)
print(blank)
Output:
[[ 0. 0. 0. 0. 0.]
[ 0. 255. 255. 255. 0.]
[ 0. 255. 255. 255. 0.]
[ 0. 255. 255. 255. 0.]
[ 0. 0. 0. 0. 0.]]

How to correctly vectorise a function using numpy?

I'm new to numpy and I must be doing something stupid here, but all I want is to generate an array of 4-dimention probability distributions. I don't understand why my vectorised function is returning this weird object which claims to be of type np.ndarray but doesn't print like one. Also, it returns error when I call self.inputSpace[:,0].
Here's the entire content of test.py:
import numpy as np
def generateDist(i,j,k):
return np.squeeze(np.array([i*j,i*(1-j),(1-i)*k,(1-i)*(1-k)]))
generateDist = np.vectorize(generateDist,otypes=[np.ndarray])
class distributionSpace():
def __init__(self):
self.grid = 3 # set to 3 for simplicity
self.inputSpace = np.array([])
def generateDistribution(self):
alpha = np.linspace(0.,1.,self.grid)
beta = np.linspace(0.,1.,self.grid)
gamma = np.linspace(0.,1.,self.grid)
i , j , k = np.meshgrid(alpha,beta,gamma)
i = np.squeeze(i.flatten())
j = np.squeeze(j.flatten())
k = np.squeeze(k.flatten())
self.inputSpace = generateDist(i,j,k)
print(self.inputSpace)
return self
if __name__ == '__main__':
distributionSpace().generateDistribution()
And here's the result I got:
$ python3 test.py
[array([ 0., 0., 0., 1.]) array([ 0. , 0. , 0.5, 0.5])
array([ 0., 0., 1., 0.]) array([ 0. , 0.5, 0. , 0.5])
array([ 0. , 0.5 , 0.25, 0.25]) array([ 0. , 0.5, 0.5, 0. ])
array([ 0., 1., 0., 0.]) array([ 0., 1., 0., 0.])
array([ 0., 1., 0., 0.]) array([ 0., 0., 0., 1.])
array([ 0. , 0. , 0.5, 0.5]) array([ 0., 0., 1., 0.])
array([ 0.25, 0.25, 0. , 0.5 ]) array([ 0.25, 0.25, 0.25, 0.25])
array([ 0.25, 0.25, 0.5 , 0. ]) array([ 0.5, 0.5, 0. , 0. ])
array([ 0.5, 0.5, 0. , 0. ]) array([ 0.5, 0.5, 0. , 0. ])
array([ 0., 0., 0., 1.]) array([ 0. , 0. , 0.5, 0.5])
array([ 0., 0., 1., 0.]) array([ 0.5, 0. , 0. , 0.5])
array([ 0.5 , 0. , 0.25, 0.25]) array([ 0.5, 0. , 0.5, 0. ])
array([ 1., 0., 0., 0.]) array([ 1., 0., 0., 0.])
array([ 1., 0., 0., 0.])]
Found an answer here for people who are searching :
Using Numpy Vectorize on Functions that Return Vectors
tl;dr:
self.inputSpace = np.array(generateDist(i,j,k).tolist())

Python - Concatenation in an array of redondant values

I would like to "concatenate" results of detections of
positions of specific values in my array "Coord3".
I have a double criteria on my array for 2 specific dimension of it.
I get some redondant positions and i would like to gather it in order to apply a mask
of this values.
As example with a moderate array :
import numpy as np
Coord3 = np.array([[[[ 0., 0.],
[ 0., 1.],
[ 0., 2.]],
[[ 1., 0.],
[ 1., 1.],
[ 1., 2.]],
[[ 2., 0.],
[ 2., 1.],
[ 2., 2.]]],
[[[ 1., 0.],
[ 1., 1.],
[ 1., 2.]],
[[ 2., 0.],
[ 2., 1.],
[ 2., 2.]],
[[ 4., 0.],
[ 3., 1.],
[ 4., 2.]]],
[[[ 2., 0.],
[ 2., 1.],
[ 2., 2.]],
[[ 3., 0.],
[ 3., 1.],
[ 3., 2.]],
[[ 4., 0.],
[ 4., 1.],
[ 4., 4.]]]])
#I apply my double criteria in 2 shapes of my array Coord3
plaY=[]
for i in range(Coord3.shape[0]):
holding_list = zip(*np.where(Coord3[i,:,:,0] > 3))
plaY.append(holding_list)
plaY_array = np.asarray(plaY)
#plaY_array
#Out[1088]: array([[], [(2, 0), (2, 2)], [(2, 0), (2, 1), (2, 2)]], dtype=object)
plaX=[]
for i in range(Coord3.shape[0]):
holding_list = zip(*np.where(Coord3[i,:,:,1] > 2))
plaX.append(holding_list)
plaX_array = np.asarray(plaX)
#plaX_array
#Out[1097]: array([[], [], [(2, 2)]], dtype=object)
So (2,0) and (2,2) are redondant and i would like to supress it and to gather all in an unique array... as :
np.array([[2, 0], [2, 2],....])
--- EDIT LATER ------------------------------------------
I could concatenate for each specific time
plaY_array = plaY_array[:,np.newaxis]
plaX_array = plaX_array[:,np.newaxis]
test = plaX_array + plaY_array
#I get that :
#test
#array([[[[]]],
#[[[(2, 0), (2, 2)]]],
#[[[(2, 0), (2, 1), (2, 2), (2, 2)]]]], dtype=object)
So now i have to suppress just the (2,2) redondant in the "third slice", it could be interesting to know the coordinates for each specific time (so i let the (2,2) in "2nd slice"
You could turn the list of coordinates into a set to remove duplicates:
In [21]: set(zip(*(np.where(Coord3[:,:,:,0] > 3)[1:])))
Out[21]: {(2, 0), (2, 1), (2, 2)}
plaY_array = np.array(list(set(zip(*(np.where(Coord3[:,:,:,0] > 3)[1:])))))
plaX_array = np.array(list(set(zip(*(np.where(Coord3[:,:,:,1] > 2)[1:])))))
print(plaY_array)
# [[2 0]
# [2 1]
# [2 2]]
print(plaX_array)
# [[2 2]]
Also note that you can eliminate the for-loop
for i in range(Coord3.shape[0]):
by calling np.where(Coord3[:,:,:,0] > 3) instead of np.where(Coord3[i,:,:,0] > 3)
for each i:
In [16]: np.where(Coord3[:,:,:,0] > 3)
Out[16]: (array([1, 1, 2, 2, 2]), array([2, 2, 2, 2, 2]), array([0, 2, 0, 1, 2]))
The i values are in the first array, but since you don't care about those, you can just drop the first array.

plot selected rows of numpy array

Consider a small numpy array:
array([[ 0., 1., 0., 1., 0., 0., 0., 0., 0., 1.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 18., 15., 25., 0., 0., 0.],
[ 0., 0., 0., 23., 19., 20., 20., 0., 0., 0.],
[ 0., 0., 20., 22., 26., 23., 18., 0., 0., 0.],
[ 0., 0., 0., 23., 16., 20., 13., 0., 0., 0.],
[ 0., 0., 0., 0., 18., 20., 18., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 1., 0., 0., 1., 0., 0., 0., 0., 0.]])
I would like to plot, let say from the row number 3 to the row number 6, i.e. a section of my numpy array(I am coming from matlab backgroud). How could I loop this? or How could I plot multiple rows of my numpy array in the same graph?
So far I have tried; I define an arbitrary x:
x = np.arange(0,10)
then If I use
plt.plot(x,data[3,:])
to plot the third row and It does fine. The problem arises if I try:
plt.plot(x,data[3:4,:])
I get the error "x and y must have same first dimension", which I understand because he stacks row number 3 and row number 4 together, so that x and y do not have the same dimension. How can I overcome that?
Thank you
As the error implies, your data.shape = (1,10) is inconsistent with your input x.shape = (10,). To solve this problem you can just transpose your data using .T, i.e.
plt.plot(x, data[3:4,:].T)
Also, keep in mind that data[3:4,:] is the same as data[3,:], you will need to use data[3:5,:] to get the 3rd and 4th rows, for example.
Just a better application of psuedocubi's answer.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,10)
y = np.array(YOUR DATA HERE)
plt.plot(x,a[3:4].T,'r--',label="x vs y1") #CONTAINS YOUR 3RD ROW
plt.plot(x,a[4:5].T,'g--',label="x vs y2") #CONTAINS YOUR 4TH ROW
plt.plot(x,a[5:6].T,'b--',label="x vs y3") #CONTAINS YOUR 5TH ROW
plt.legend(loc='best')
plt.xlabel("x")
plt.ylabel("y")
plt.show()
The x here as been plotted with your own data!
You can try:
for i in range(3):
plt.plot( x , data[ i , : ] )
plt.show()
If you want a range of rows ,for example from 3 to 6 , you can use:
range(3,7,1) , where 1 is the step , 3 is the starting row and 7 is the last row we want to plot (6 ) plus one

Pick up elements of a numpy array for defined intervals

I have two 1-D arrays of array objects (DATA and DEGREE) of the same size. Both arrays are collection of 8 other arrays :
DATA = array([array([ 22.]),
array([ 26., 16., 23., 0., 20., 23., 0., 19.]),
array([ 0., 0., 0., 0., 20., 0., 0., 18., 18., 0., 0.,
0., 23., 20., 20., 15.]),
array([ 20., 0., 0., 18., 0., 13., 0., 0., 0., 0., 0.,
0., 25., 18., 0., 0., 0., 0., 0., 0.]),
array([ 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 1., 0.]),
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0.]),
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0.]),
array([ 1., 0.])], dtype=object)
DEGREE = array([array([0]),
array([ 0, 45, 90, 135, 180, -90, -135, -45]),
array([-153, -90, -116, -135, 26, 116, 90, -63, 63, 180, 153,
135, 0, -26, 45, -45]),
array([ -18, 123, 56, 0, 161, 18, 180, 90, -56, -161, 71,
146, -33, 33, -123, -146, 108, -108, -71, -90]),
array([ 14, -104, -116, -90, 75, 135, -75, -63, 45, 63, -14,
26, -135, -45, 0, 90, -26, 116, 104]),
array([ 30, 53, 45, 126, 36, -126, 21, -53, 11, -45, 0,
-36, -11, -30, -21]),
array([-38, -26, 26, -18, -9, 38, 0, 9, 18]),
array([-33, 33])], dtype=object)
I would like to pick up the elements of DATA array corresponding to those of the DEGREE array defining a certain "alpha" angle interval. For example, for -90<=alpha<-70 I should get the Output array reported below. When no angles are found for a certain angle interval the algorithms should return zero, for example in the case of the first array of the Output.
Output = array([array([0]),
array([23]),
array([0]),
array([0]),
array([1,0]),
array([0]),
array([0]),
array([0])], dtype=object)
The idea would be to have alpha varying between -90 and +90 with steps of 20 degrees, i.e. -90<=alpha<-70, -70<=alpha<-50, -50<=alpha<-30 and so on to have finally 9 Output arrays. How could I do that? Thank you in advance
I think your best bet is to use list comprehensions and masks. The following should do the trick:
import numpy as np
def val_check(val_in):
''' Check for non-zero values in numpy array '''
if val_in.any():
return val_in
else:
return np.array([0])
# Set tuples of desired ranges
angles = []
angle = -90
while angle < 90:
angles.append((angle, angle + 20))
angle = angle + 20
out = []
for ang in angles:
# List comprehensions to get masks for elements in desired range per array
mask = [(arr >= ang[0]) * (arr < ang[1]) for arr in DEGREE]
mask_index = [np.where(m) for m in mask]
# Include data corresponding to masks
out_temp = [dat[mi[0]] for (dat, mi) in zip(DATA, mask_index)]
# Replace empty elements with np.array([0])
out_temp = np.array([val_check(ot) for ot in out_temp])
out.append(out_temp)
If you want the output as an array instead of a list, include one final line out = np.array(out)

Resources