How to visualize 2d array of doubles in vtk? - c++

I have 2d array (of size 20x30) of doubles:
double a[20*30];
How to visualize it using VTK? It is extremely difficult to find proper documentation. The closest example which I found is this, however it uses as input 3 unsigned chars which represents color. As I understand I should use vtkScalarsToColors class to somehow map scalars to colors, but I can't figure out how to put everything into single piece of code.

What you probably want to do is to assign scalars to points or cells of a surface or volume mesh. VTK then can take care of the visualization. This is demonstrated in the following example: ScalarBarActor. For the basic usage, follow the Scalars example.
However, you need to provide the suitable mesh yourself to which you want to map the values. From your question, it is not entirely clear what you mean with "how to visualize a 2d array" of values. If you want to assign scalar values in a planar 20x30 grid, you need to first create a surface object (of type vtkPolyData) with triangular or quadrangular cells, and then assign the values to the points of the mesh using surface->GetPointData()->SetScalars(), as demonstrated in the above examples.
Convenient in this case would be the vtkPlaneSource, look here for the corresponding example. The number of grid points you can set by using SetXResolution() or SetYResolution() respectively. (In case this is not clear: vtkPlaneSource inherits vtkPolyDataAlgorithm, to access the underlying vtkPolyData object, use the method GetOutput())
Update: I added sample code that demonstrates the procedure - in python, for better readability.
# This code has been written by normanius under the CC BY-SA 4.0 license.
# License: https://creativecommons.org/licenses/by-sa/4.0/
# Author: normanius: https://stackoverflow.com/users/3388962/normanius
# Date: August 2018
# Reference: https://stackoverflow.com/a/51754466/3388962
import vtk
import numpy as np
###########################################################
# CREATE ARRAY VALUES
###########################################################
# Just create some fancy looking values for z.
n = 100
m = 50
xmin = -1; xmax = 1
ymin = -1; ymax = 1
x = np.linspace(xmin, xmax, n)
y = np.linspace(ymin, ymax, m)
x, y = np.meshgrid(x, y)
x, y = x.flatten(), y.flatten()
z = (x+y)*np.exp(-3.0*(x**2+y**2))
###########################################################
# CREATE PLANE
###########################################################
# Create a planar mesh of quadriliterals with nxm points.
# (SetOrigin and SetPointX only required if the extent
# of the plane should be the same. For the mapping
# of the scalar values, this is not required.)
plane = vtk.vtkPlaneSource()
plane.SetResolution(n-1,m-1)
plane.SetOrigin([xmin,ymin,0]) # Lower left corner
plane.SetPoint1([xmax,ymin,0])
plane.SetPoint2([xmin,ymax,0])
plane.Update()
# Map the values to the planar mesh.
# Assumption: same index i for scalars z[i] and mesh points
nPoints = plane.GetOutput().GetNumberOfPoints()
assert(nPoints == len(z))
# VTK has its own array format. Convert the input
# array (z) to a vtkFloatArray.
scalars = vtk.vtkFloatArray()
scalars.SetNumberOfValues(nPoints)
for i in range(nPoints):
scalars.SetValue(i, z[i])
# Assign the scalar array.
plane.GetOutput().GetPointData().SetScalars(scalars)
###########################################################
# WRITE DATA
###########################################################
writer = vtk.vtkXMLPolyDataWriter()
writer.SetFileName('output.vtp')
writer.SetInputConnection(plane.GetOutputPort())
writer.Write() # => Use for example ParaView to see scalars
###########################################################
# VISUALIZATION
###########################################################
# This is a bit annoying: ensure a proper color-lookup.
colorSeries = vtk.vtkColorSeries()
colorSeries.SetColorScheme(vtk.vtkColorSeries.BREWER_DIVERGING_SPECTRAL_10)
lut = vtk.vtkColorTransferFunction()
lut.SetColorSpaceToHSV()
nColors = colorSeries.GetNumberOfColors()
zMin = np.min(z)
zMax = np.max(z)
for i in range(0, nColors):
color = colorSeries.GetColor(i)
color = [c/255.0 for c in color]
t = zMin + float(zMax - zMin)/(nColors - 1) * i
lut.AddRGBPoint(t, color[0], color[1], color[2])
# Mapper.
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(plane.GetOutputPort())
mapper.ScalarVisibilityOn()
mapper.SetScalarModeToUsePointData()
mapper.SetLookupTable(lut)
mapper.SetColorModeToMapScalars()
# Actor.
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Renderer.
renderer = vtk.vtkRenderer()
renderer.SetBackground([0.5]*3)
# Render window and interactor.
renderWindow = vtk.vtkRenderWindow()
renderWindow.SetWindowName('Demo')
renderWindow.AddRenderer(renderer)
renderer.AddActor(actor)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderWindow.Render()
interactor.Start()
The result will look similar to this:

Related

How to convert 2d(x,y) cooridinates into 3d(x,y,z) coordinates using python and point cloud?

I have been using this github repo: https://github.com/aim-uofa/AdelaiDepth/blob/main/LeReS/Minist_Test/tools/test_shape.py
To figure out how this piece of code can be used to get x,y,z coordinates:
def reconstruct_3D(depth, f):
"""
Reconstruct depth to 3D pointcloud with the provided focal length.
Return:
pcd: N X 3 array, point cloud
"""
cu = depth.shape[1] / 2
cv = depth.shape[0] / 2
width = depth.shape[1]
height = depth.shape[0]
row = np.arange(0, width, 1)
u = np.array([row for i in np.arange(height)])
col = np.arange(0, height, 1)
v = np.array([col for i in np.arange(width)])
v = v.transpose(1, 0)
I want to use these coordinates to find distance between 2 people in 3D for an object detection model. Does anyone have any advice?
I know how to use 2d images with yolo to figure out distance between 2 people. Based on this link: Compute the centroid of a rectangle in python
My thinking is i can use the bounding boxes to get corners and then find the centroid and do that for 2 bounding boxes of people and use triangulation to find the hypotenuse between the 2 points (which is their distance).
However, i am having a tricky time on how to use a set of 3d coordinates to find distance between 2 people. I can get the relative distance from my 2d model.
By having a 2D depth image and camera's intrinsic matrix, you can convert each pixel to 3D point cloud as:
z = d
x = (u - cx) * z / f
y = (v - cy) * z / f
// where (cx, cy) is the principle point and f is the focal length.
In the meantime, you can use third party library like open3d for doing the same:
xyz = open3d.geometry.create_point_cloud_from_depth_image(depth, intrinsic)

Why are my X and Y values always out of range of my raster file size?

I have converted quite a few WGS84 coordinates, that I know exist within my raster data, to UTM and have plugged them into my program only to have it tell me they are out of range. My raster is 4695x9798 and I'm not sure why my coordinates keep falling outside of that window
import numpy as np
from osgeo import gdal,ogr
import struct
gdata = gdal.Open('sinusoidal.tif')
geot = gdata.GetGeoTransform()
x = (284905 - geot[0])/geot[1]
y = (5936117 - geot[3])/(geot[5])
myarray = np.array(gdata.GetRasterBand(1).ReadAsArray())
print gdata.RasterXSize
print gdata.RasterYSize
rb = gdata.GetRasterBand(1)
intval = rb.ReadAsArray(x,y,1,1)
print intval
Error Message:
Access window out of range in RasterIO(). Requested
(6126,1437) of size 1x1 on raster of 4695x9798.
The error description is very explicit. You are requesting a pixel that is outside of your raster extent. This may be related to the UTM coordinates you are supplying, or some aspect of the geotransform you are not taking into consideration (xskew or yskew). The more canonical way to get the row-col pixel indices is to use the inverse geotransform.
#...
rb = gdata.GetRasterBand(1)
geot = gdata.GetGeoTransform() # maps i,j to x,y
# try-except block to handle different output of InvGeoTransform with gdal versions
try:
inv_gt_success, inverse_gt = gdal.InvGeoTransform(geot) # maps x,y to i,j
except:
inverse_gt = gdal.InvGeoTransform(geot) # maps x,y to i,j
x_utm = 284905
y_utm = 5936117
pix_x = int(inverse_gt[0] + inverse_gt[1] * x_utm +
inverse_gt[2] * y_utm)
pix_y = int(inverse_gt[3] + inverse_gt[4] * y_utm +
inverse_gt[5] * y_utm)
val = rb.ReadAsArray(pix_x, pix_y, 1, 1)[0,0]

Object Looking Skewed After Essential Matrix Calculation and Projection

I am trying to calculate an essential and a projection matrix from two images. I will then use them to project a 3D object onto the image. The two images I used are
I picked a few pixel correspondences, and fed that to a SVD based least square mechanism which the books say gives me the essential matrix. I used the code below for this task (code is based mostly on Eric Solem's Programming Computer Vision with Python book):
import scipy.linalg as lin
import pandas as pd
def skew(a):
return np.array([[0,-a[2],a[1]],[a[2],0,-a[0]],[-a[1],a[0],0]])
def essential(x1,x2):
n = x1.shape[1]
A = np.zeros((n,9))
for i in range(n):
A[i] = [ x1[0,i]*x2[0,i], \
x1[0,i]*x2[1,i], \
x1[0,i]*x2[2,i], \
x1[1,i]*x2[0,i], \
x1[1,i]*x2[1,i], \
x1[1,i]*x2[2,i], \
x1[2,i]*x2[0,i], \
x1[2,i]*x2[1,i], \
x1[2,i]*x2[2,i]]
U,S,V = lin.svd(A)
F = V[-1].reshape(3,3)
return F
def compute_P_from_essential(E):
U,S,V = lin.svd(E)
if lin.det(np.dot(U,V))<0: V = -V
E = np.dot(U,np.dot(np.diag([1,1,0]),V))
Z = skew([0,0,-1])
W = np.array([[0,-1,0],[1,0,0],[0,0,1]])
P2 = [np.vstack((np.dot(U,np.dot(W,V)).T,U[:,2])).T,
np.vstack((np.dot(U,np.dot(W,V)).T,-U[:,2])).T,
np.vstack((np.dot(U,np.dot(W.T,V)).T,U[:,2])).T,
np.vstack((np.dot(U,np.dot(W.T,V)).T,-U[:,2])).T]
return P2
points = [ \
[266,163,296,160],[265,237,297,266],\
[76,288,51,340],[135,31,142,4],\
[344,167,371,156],[48,165,71,164],\
[151,68,166,56],[237,26,259,19],\
[226,147,254,140]]
df = pd.DataFrame(points)
df['uno'] = 1.
x1 = np.array(df[[0,1,'uno']].T)
x2 = np.array(df[[2,3,'uno']].T)
print x1
print x2
E = essential(x1,x2)
P = compute_P_from_essential(E)
import pandas as pd
x0 = 3.; y0 = 1.; z0 = 1.
print df.shape
e = 1
cube = [[x0,y0,z0],[x0+e,y0,z0],[x0+e,y0+e,z0],[x0,y0+e,z0],
[x0,y0,z0+e],[x0+e,y0,z0+e],[x0+e,y0+e,z0+e],[x0,y0+e,z0+e]]
cube = pd.DataFrame(cube)
cube['1'] = 1.
xx = np.dot(P[1], cube.T) * 100.
xx[1,:] = 360-xx[1,:]
#xx = xx / xx[2]
print xx[0].shape
plt.plot(xx[0], xx[1],'.')
plt.xlim(0,640)
plt.ylim(0,360)
I calculated the essential matrix, then the projection matrix, then used that to project a 3D cube. The result:
This looks skewed, I am not sure why this happened. Any ideas on how to fix this?
Thanks,
First of all, it looks like you are computing the essential matrix using exactly 9 points. You can do this using only 8 (since scale is a free parameter, you can multiply the essential by a scalar and it will stay the same so you can fix one of the parameters and just use 8 points, but I digress.) However, in practice this is a very bad idea because your 8 points might have poor spatial configuration. So what you want to do is to select N matches (600 for example), and use an algorithm like RANSAC to determine the best Essential matrix. But aside from that, what I'd recommend to debug such applications is this: compute the Fundalental matrix F based on the Essential you just computed. Now you can select a point in image 1 and then display the corresponding epipolar line in the second one. That will help you visually evaluate and thus debug the estimation of the Essential.

How numpy decides number of coefficient in smooth bivariate spline?

I am using SmoothBivariateSpline of numpy library to get a surface fit of a data.
By default degrees of bivariate spline is 3. When i am fitting my data, if the degree is 3, i should get 16 coefficients and 8 knot points in x and y direction respectively. This is happening for one of the spline fit (f1). But i am getting 25 coefficients and 9 knot points for the second fit (f2).
Can someone please tell me why i am getting more number of coefficients?? if you want i can share my data file as well.
here is my code
import numpy as np
# loading the txt file from where i am reading data
L = np.loadtxt('DATA_File_PT.txt')
P = L[:,0] # pressure
T = L[:,1] # temperature
H = L[:,2] # enthalpy
Rho = L[:,3] # density
# fitting Spline for each set (I have P and T as independent variable, H and Rho are dependent)
f1 = interpolate.SmoothBivariateSpline(P, T, H, kx=3, ky=3)
f2 = interpolate.SmoothBivariateSpline(P, T, Rho, kx=3, ky=3)
o1=f1.get_knots()
coeff1 = f1.get_coeffs()
o2=f2.get_knots()
coeff2 = f2.get_coeffs()

Colouring the surface of a sphere with a set of scalar values in matplotlib

I am rather new to matplotlib (and this is also my first question here). I'm trying to represent the scalp surface potential as recorded by an EEG. So far I have a two-dimensional figure of a sphere projection, which I generated using contourf, and pretty much boils down to an ordinary heat map.
Is there any way this can be done on half a sphere?, i.e. generating a 3D sphere with surface colours given by a list of values? Something like this, http://embal.gforge.inria.fr/img/inverse.jpg, but I have more than enough with just half a sphere.
I have seen a few related questions (for example, Matplotlib 3d colour plot - is it possible?), but they either don't really address my question or remain unanswered to date.
I have also spent the morning looking through countless examples. In most of what I've found, the colour at one particular point of a surface is indicative of its Z value, but I don't want that... I want to draw the surface, then specify the colours with the data I have.
You can use plot_trisurf and assign a custom field to the underlying ScalarMappable through set_array method.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
(n, m) = (250, 250)
# Meshing a unit sphere according to n, m
theta = np.linspace(0, 2 * np.pi, num=n, endpoint=False)
phi = np.linspace(np.pi * (-0.5 + 1./(m+1)), np.pi*0.5, num=m, endpoint=False)
theta, phi = np.meshgrid(theta, phi)
theta, phi = theta.ravel(), phi.ravel()
theta = np.append(theta, [0.]) # Adding the north pole...
phi = np.append(phi, [np.pi*0.5])
mesh_x, mesh_y = ((np.pi*0.5 - phi)*np.cos(theta), (np.pi*0.5 - phi)*np.sin(theta))
triangles = mtri.Triangulation(mesh_x, mesh_y).triangles
x, y, z = np.cos(phi)*np.cos(theta), np.cos(phi)*np.sin(theta), np.sin(phi)
# Defining a custom color scalar field
vals = np.sin(6*phi) * np.sin(3*theta)
colors = np.mean(vals[triangles], axis=1)
# Plotting
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
cmap = plt.get_cmap('Blues')
triang = mtri.Triangulation(x, y, triangles)
collec = ax.plot_trisurf(triang, z, cmap=cmap, shade=False, linewidth=0.)
collec.set_array(colors)
collec.autoscale()
plt.show()