Mapping values from NP ARRAY to STL - python

Recently i was struggling trying to take the pixel values of a 3D volume (np array) using specific space coordinate of a STL object.
The STL object is spatially overlapped with the 3D volume but the latter has no coordinate and so i don't know how to pick pixel values corresponding to the STL coordinates.
Any idea?

If the STL object is truly in the 3d volume's coordinate space, then you can simply STL's coordinate as an index to lookup the value from the 3d array. This lookup does nearest neighbor interpolation of the 3d image. For better looking results you'd want to do linear (or even cubic) interpolation of the nearby pixels.
In most 3d imaging tasks, those coordinate spaces do not align. So there is a transform to go from world space to 3d volume space. But if all you have is a 3d numpy array, then there is no transformation information.
Update:
To index into the 3d volume take the X, Y, Z coordinates of your point from the STL object and convert them into integer value I, J, K. Then lookup in the numpy array using I,J,K as indices: np_array[K][J][I]. I think you have to reverse the order of the indices because of the array ordering numpy uses.
When you way 3d array and the STL align in python, how are you showing that? The original DICOM or Nifti certainly have world coordinate transformations in the metadata.

Related

Slicing in a non-orthogonal plane from a 3D volume (Python)

I am trying to write a function that extracts a 2D slice in a non-orthogonal plane from a 3D volume using numpy. The non-orthogonal slice obtained should be a rectangular two-dimensional array of shape (n, m), while the input volume should be a three-dimensional numpy array of shape (i, j, k).
So far I have tried to create a function that receives the volume, the plane normal and a point that belongs to the plane as inputs. I'm representing the plane normal and the point with numpy arrays of shape (3,). I am quite certain the function should follow these steps:
The function should first create a grid with the indices of the volume coordinates.
The function should define the plane using the dot product of the normal and the point.
The function should find the coordinates of the bounding box that contains the entire image slice. It is important to note that, except for specific edge cases where one of the normal coefficients is 0, most bounding boxes should end up with its corners having a variable amount of coordinates from outside the image.
The function should interpolate the slice points from the bounding box using the volume, as some of the coordinates contained by the slice may not be integers and thus will not actually exist in the image.
The non-orthogonal slice obtained from interpolation should then be returned.
I am stuck at step 3. I have gotten steps 4 and 5 to work using orthogonal planes, which are easy to obtain using numpy slicing, but I have been stuck for days trying to get my head around how to find the bounding box coordinates (even though I do not think this should be a hard problem). Any help would be greatly welcome!

Plot 3D mesh using 3D numpy array and 2D numpy array

I have a 3D numpy array Lattice[][][], and a 2D numpy array Trajectory[][].
I want the indices i/j/k of Lattice to be the coordinate axes and the value contained in the tensor element to be plotted as a colored dot, making a 3D mesh maybe
and I want to plot Trajectory where the Trajectory[p][0]/[1]/[2] contains the coordinates, and the index p is the iteration number - so this I want to plot as a 3D line, hopefully inside the mesh. I have no idea from where to start, is it possible in matplotlib?
You could definetly use matplotlib. Check this link: https://matplotlib.org/2.0.2/mpl_toolkits/mplot3d/tutorial.html
But you could also try a different package, like Plotly: https://plotly.com/python/3d-charts/

Determine Coordinates on Gridded Data to Find Lengths of Objects

I'm in the process of identifying objects whose float value is greater than a certain threshold in a 2-D numpy array. I then need to determine the length of the major axis of each object and make sure that the object's major axis length satisfies a certain threshold in kilometers.
I am able to identify the objects I want in my 2-D numpy array by using the scipy.ndimage.measurements.label module. I then am able to determine the length of each object's major axis using the scikit-image regionprops module (skimage.measure.regionprops).
However, I am unsure about what the units of the object's length are as the 2-D numpy array by itself does not have any information about coordinates. The 2-D numpy array is essentially a dataset that maps to a subdomain on the surface of the globe. Additionally, I have two other 2-D numpy arrays that are the same size as my data array with one array containing the latitude coordinates for each grid point and the other containing the longitude coordinates. I believe I somehow need to use the lat/lon arrays to determine the length of the major axis of my objects but I have no idea how.
This is the code I have so far:
from scipy import ndimage
from skimage.measure import regionprops
import numpy as np
# 2-D numpy array with data.
data
# 2-D numpy arrays with latitude and longitude coordinates that are same grid as data array.
lat
lon
# Allow label module to have diagonal object matching.
struct = np.ones((3,3), dtype=bool)
# Find objects in data array.
labl, n_features = ndimage.measurements.label(data>=35,structure=struct)
# Find major axis length in labl array for each object found.
props = regionprops(labl)
# Loop through each object.
for p in props:
# Find object's major axis length.
length = p.major_axis_length
(some code to compute major axis length in kilometers?)
if length < 125: #(125 is in km)
(keep object)
Any help would be greatly appreciated. Thanks!

Indexing / interpolation

I am working on a image processing script that takes some pixel values and changes their location. my script returns me with pixel locations that arent integers, making it impossible to create an image array where I can simply plug in the piel value at their respective index.
I am looking to interp2d to do this.
for example I have a x,y,value matrix called 'scan'
scan=[[1.25, 1.25, 49],[4.65, 6.34, 154]...etc]]
scan[:,0]=Xs #array of x values
scan[:,1]=Ys #array of y values
scan[:,2]=Vs #array of pixel values
which I need to interpolate onto a uniform 10x10 grid to show as an image.
I am currently trying to use interp2d as
f=interpolate.interp2d(scan[:,0],scan[:,1],scan[:,2])
image=f(range(10),range(10))
I have many points, some are in and out of bounds of the uniform image i am trying to map to
Thanks,
Niall

GDAL Affine Coefficients from Lat/Lon Meshgrids in Python

I am having some problems with Affine tranformation coefficients while creating a new GeoTIFF file. What I am doing is ETL on a scientific dataset that results in a 2D Ndarray along with a set of meshgrid Ndarrays that contain Lat and Lon. Both the meshgrids and the dataset arrays have the same dimensions of 645 x 980. From what I understand the GeoTIFF requires a list of Affine coefficients when created from Python GDAL via the SetGeoTransform() method. The list has the form of [xllcorner, xrotation, x_cellsize, yllcorner, yrotation, y_cellsize]. My approach to this is similar to what is outlined here: http://adventuresindevelopment.blogspot.com/2008/12/python-gdal-adding-geotiff-meta-data.html
At this point is where I run into problems. I calculate the xllcorner and the yllcorner using the min() method for the two meshgrid arrays for lat & lon respectively, and I manually calculate the x and y cellsize by applying the formula [max-min]/dimension size with the x dimension size being the x axis size for the lons meshgrid and the y dimension size being the y axis size for the lats meshgrid. When I apply this method and try to write out the array band via GetRasterBand().WriteArray() I get this error message:
Traceback (most recent call last):
...
raise ValueError("array larger than output file, or offset off edge")
ValueError: array larger than output file, or offset off edge
Therefore I assume that I have composed my affine coefficients incorrectly but given the data this makes no sense to me. I even made sure that the Spatial Reference System was set to WGS:84 before attempting the affine coefficient creation. So my question is how to properly create the Affine coefficients with lat/lon meshgrids and a data array that share common dimensions? I think my cell size calculation can't simply be lat/lon differences; but I am not sure.
This error is typically shown when the expected array shape does not match. For instance, see what shape the expected shape is with:
band = src.GetRasterBand(1)
arr = band.ReadAsArray()
print(arr.shape) # (656L, 515L)
This will need to be the shape of the numpy array to be written:
assert other_array.shape == arr.shape
band.WriteArray(other_array)
And to raise the same ValueError, change the shape so it is longer in one dimension, e.g.:
band.WriteArray(other_array.T)
As for affine transformations, this is probably not raising any errors, as it is often just stored as data. GIS rasters typically register the world coordinate in the upper-left corner, and use a -dy value to count rows downwards. However, using a lower-left corner with +dy is usually fine by most software. It will just be upside down when comparing the array as a printed matrix versus mapped raster.

Categories

Resources