VTK vtkDataSet to 3D numpy array and back - python

I'm moving my first steps into vtk and I'm quite struggling given the lack of documentation.
I've got a .vtk file which is a vtkDataSet type object I haven't created. I would need to export the content of it and convert it to a 3D numpy matrix, customise it and its tensor and write everything in a vtkDataSet object and .vtk file.
What I've ended up so far is save the coordinates, which is not what I need, of the points into a numpy array using vtk.util.numpy_support vtk_to_numpy. However, I'd need a 3D numpy matrix representing the volume rendering of it.
Speaking about the tensor, I figured out how and where to save my 9-elements tensor into the file. I'm just not sure on how to set it properly to be related to the points.
The last step, which is 3D numpy array to vtk, looks feasible using numpy.ravel and numpy_to_vtk from vtk.util.numpy_support.
Here's some code I'm using as a test:
# reader for mrtrix vtk file
reader = vtk.vtkDataSetReader()
file_name = 'my_file.vtk'
reader.SetFileName(file_name)
reader.Update()
# get the vtkDataArray
data_set = reader.GetOutput()
# these are the coordinates of the points
# I'd need the 3D numpy volume rendering matrix instead
point_array = data_set.GetPoints().GetData()
# test tensor
# I'd need to save a tensor for every element of the 3D numpy matrix
tensor = numpy_to_vtk(np.zeros([data_set.GetNumberOfPoints(), 9]))
tensor.SetName('Tensors_')
point_data = data_set.GetPointData()
point_data.SetAttribute(tensor, 4)

This may be useful in your case:
https://github.com/marcomusy/vedo/blob/master/vedo/examples/volumetric/numpy2volume1.py
and retrieve the numpy object with e.g.
print('numpy array from Volume:', vol.getPointArray().shape)

Related

Problems with obtaining and saving 2D slices from a 3D array

I'm trying to save a 2D slice of a 3D array that I'm slicing with the following code:
import nibabel as nib
import numpy as np
from nibabel.testing import data_path
import os
vol1= np.load("teste01.npy")
zSlice= (vol1[1, :, :]).squeeze()
print (zSlice.shape)
np.save(zSlice, os.path.join("D:/Volumes convertidos LIDC/slice01.npy"))
I'm getting an error: TypeError: expected str, bytes or os.PathLike object, not ndarray
Is there any way to fix this? I need 2D arrays in order to be able to insert my images into an automatic lung vessel segmentation model but I only have 3D images, is there any way to obtain all the slices from said 3D image instead of slicing it manually (like I'm trying to do?
You just mixed up the parameters for numpy.save. Use the filename as the first parameter and the data as the second:
np.save(os.path.join("D:/Volumes convertidos LIDC/slice01.npy"), zSlice)

Python: Read vtk file, add data set then write vtk

I have an exisiting vtk file (of a FE mesh, regular hexahedron mesh) and I would like to add a data set to this that I have in Python. Specifically, I would like to add this numpy data set to each node and then visualize it in ParaView.
Any tips on how I can get started on this?
VTK (and by extension ParaView) has great NumPy integration facilities. For a wonderful overview on these, please see the blog post series starting with Improved VTK – numpy integration].
The important parts are:
You need to wrap your VTK data object in an adapter class
You add your NumPy array to the wrapped data set
Sketching this out, you can write:
import vtk
from vtk.numpy_interface import dataset_adapter as dsa
dataSet = ...
numpyArray = ...
adaptedDataSet = dsa.WrapDataObject(dataSet)
dataSet.PointData.append(numpyArray, 'arrayname')
If your data were instead associated with cells rather than points, you would change that last line to
dataSet.CellData.append(numpyArray, 'arrayname')
You'll have to be sure that the order of the data in the NumPy array matches the order of points in the hexahedron mesh.
Now, how do you do this in ParaView? You can add a Programmable Filter. The Python environment in which the script set on the Programmable Filter is executed already does this wrapping for you, so you can simplify the script above to:
# Shallow copy the input data to the output
output.VTKObject.ShallowCopy(inputs[0].VTKObject)
# Define the numpy array
numpyArray = ...
# Add the numpy array as a point data set
output.PointData.append(numpyArray, 'arrayName')
In the script above, output is a wrapped copy of the dataset produced by the Programmable Filter, saving you from having to do the wrapping manually. You do need to shallow copy the input object to the output as the script shows.
Thanks for your assistance. Here is how I solved my problem:
import vtk
from vtk.numpy_interface import dataset_adapter as dsa
# Read in base vtk
fileName = "Original.vtk"
reader = vtk.vtkUnstructuredGridReader()
reader.SetFileName(fileName)
reader.Update()
mesh = reader.GetOutput()
# Add data set and write VTK file
meshNew = dsa.WrapDataObject(mesh)
meshNew.PointData.append(NewDataSet, "new data")
writer = vtk.vtkUnstructuredGridWriter()
writer.SetFileName("New.vtk")
writer.SetInputData(meshNew.VTKObject)
writer.Write()

How can I cut a portion of a satellite image based on coordinates? (gdal)

I have a satellite image of 7-channels (Basically I have seven .tif files, one for each band). And I have a .csv file with coordinates of points-of-interest that are in the region shot by the satellite. I want to cut small portions of the image in the surroundings of each coordinate point. How could I do that?
As I don't have a full working code right now, it really doesn't matter the size of those small portions of image. For the explanation of this question let's say that I want them to be 15x15 pixels. So for the moment, my final objective is to obtain a lot of 15x15x7 vectors, one for every coordinate point that I have in the .csv file. And that is what I am stucked with. (the "7" in the "15x15x7" is because the image has 7 channels)
Just to give some background in case it's relevant: I will use those vectors later to train a CNN model in keras.
This is what I did so far: (I am using jupyter notebook, anaconda environment)
imported gdal, numpy, matplotlib, geopandas, among other libraries.
Opened the .gif files using gdal, converted them into arrays
Opened the .csv file using pandas.
Created a numpy array called "imagen" of shape (7931, 7901, 3) that will host the 7 bands of the satellite image (in form of numbers). At this point I just need to know which rows and colums of the array "imagen" correspond to each coordinate point. In other words I need to convert every coordinate point into a pair of numbers (row,colum). And that is what I am stucked with.
After that, I think that the "cutting part" will be easy.
#I import libraries
from osgeo import gdal_array
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import geopandas
from geopandas import GeoDataFrame
from shapely.geometry import Point
#I access the satellite images (I just show one here to make it short)
b1 = r"E:\Imágenes Satelitales\2017\226_86\1\LC08_L1TP_226086_20170116_20170311_01_T1_sr_band1.tif"
band1 = gdal.Open(b1, gdal.GA_ReadOnly)
#I open the .csv file
file_svc = "C:\\Users\\Administrador\Desktop\DeepLearningInternship\Crop Yield Prediction\Crop Type Classification model - CNN\First\T28_Pringles4.csv"
df = pd.read_csv(file_svc)
print(df.head())
That prints something like this:
Lat1 Long1 CropingState
-37.75737 -61.14537 Barbecho
-37.78152 -61.15872 Verdeo invierno
-37.78248 -61.17755 Barbecho
-37.78018 -61.17357 Campo natural
-37.78850 -61.18501 Campo natural
#I create the array "imagen" (I only show one channel here to make it short)
imagen = (np.zeros(7931*7901*7, dtype = np.float32)).reshape(7931,7901,7)
imagen[:,:,0] = band1.ReadAsArray().astype(np.float32)
#And then I can plot it:
plt.imshow(imagen[:,:,0], cmap = 'hot')
plt.plot()
Which plots something like this:
(https://github.com/jamesluc007/DeepLearningInternship/blob/master/Crop%20Yield%20Prediction/Crop%20Type%20Classification%20model%20-%20CNN/First/red_band.png)
I want to transform those (-37,-61) into something like (2230,1750). But I haven't figured it how yet. Any clues?

Plot 3d volumetric data represented by a 3D numpy array

I've seen that vtkplotter supports a wide range of volumetric image formats, but does it support plotting numpy arrays? I have an image in a .mhd format that I converted to .npz file and would like to plot it using the mentioned library. Is there a way to do so?
import numpy as np
data = np.zeros((3,3,3))
# how to plot this?
If you know any other tools for visualizing volumetric data, suited for medical analysis, please tell so. I've tried mayavi but it consumes so much memory that it crashes my computer.
You can use numpy_support to convert numpy arrays to vtkImageData (i.e. a VTK 3D image).
An example follows, there's a numpy warning about type conversion: I don't think it's relevant but I'm not a python guru...
from vtk.util import numpy_support
import vtk
import numpy as np
data = np.zeros((3,3,3))
# vtkImageData is the vtk image volume type
imdata = vtk.vtkImageData()
# this is where the conversion happens
depthArray = numpy_support.numpy_to_vtk(data.ravel(), deep=True, array_type=vtk.VTK_DOUBLE)
# fill the vtk image data object
imdata.SetDimensions(data.shape)
imdata.SetSpacing([1,1,1])
imdata.SetOrigin([0,0,0])
imdata.GetPointData().SetScalars(depthArray)
# f.ex. save it as mhd file
writer = vtk.vtkMetaImageWriter()
writer.SetFileName("test.mhd")
writer.SetInputData(imdata)
writer.Write()
... and to visualize vtk volume data you can use Paraview.

Tiff to array - error

Hello, I have some problem with converting Tiff file to numpy array.
I have a 16 bit signed raster file and I want to convert it to numpy array.
I using to this gdal libarary.
import numpy
from osgeo import gdal
ds = gdal.Open("C:/.../dem.tif")
dem = numpy.array(ds.GetRasterBand(1).ReadAsArray())
At first glance, everything converts well, but I compared the result obtained in python with result in GIS software and I got different results.
Python result
Arcmap result
I found many value in numpy array that are below 91 and 278 (real min and max values), that should not exist.
GDAL already returns a Numpy array, and wrapping it in np.array by default creates a copy of that array. Which is an unnecessary performance hit. Just use:
dem = ds.GetRasterBand(1).ReadAsArray()
Or if its a single-band raster, simply:
dem = ds.ReadAsArray()
Regading the statistics, are you sure ArcMap shows the absolute high/low value? I know QGIS for example often draws the statistics from a sample of the dataset (for performance) and depending on the settings sometimes uses a percentile (eg 1%, 99%).
edit: BTW, is this a public dataset? Like an SRTM tile? It might help if you list the source.

Categories

Resources