How to calculate spatial coordinate in Image coordinate system by having spatial coordinate in RAS coordiane ststem?

Hello Dear Developers and Users

I have a number of points (approximately 48000 points). I think that their spatial coordinates are in RAS coordinate system, for example:

-146.4141082763672 66.66109466552734 -923.0950927734375

Now I want to have the coordinates of these points in the Image coordinate system.

For example, I have shown one of these points in the following figure in the center of sphere (red color).

I would like to have a row, column, and slice that is spatially positioned at this point in Python as shown in the cursor location:
B CT_wholeLung (81, 294, 11)

Please guide me.
Best regards.
Shahrokh

I think the simplest method is to create a makerup with you data and then open ‘show slice intersections’ if you just tend to get a slice window.

Hello Dear Li
Thank you for your help.

Due to the large number of points (48000 points), I think I should use the functions in Python modules such as ITK to convert RAS to IJK.

sorry,
ras0=[0,0,0]
and you could get the coordinate values based on the obove method: d=[x,y,x]

if the image spacing: sX,sY,sZ=0.582,0.582,0.625
then CX,CY,CZ=1/sX,1/sY,1/sZ

finally:
if the ras=[a,b,c]
then:D=[x+aCX,y+bCY,z+c*CZ]

1 Like

and you should use int() for the finally valume

1 Like

The beauty of homogeneous coordinates is that you transform all your points from RAS to IJK coordinate system by putting your points into a 4xN matrix and multiply it from the left using IJKToRAS matrix.

Normally you store this many points in a model node and then apply all kinds of operations on them in bulk. Where are your points coming from? What do you plan to do with them?

Hello
Dear Andras and Li

Thank you very much for your guidance and sorry for the late reply.
I want to use the particles system resulting from Chest Imaging Platform (CIP) in classification based on particles properties. These properties can indicate the features of the blood vessels of the lungs.

The output of CIP is in vtk format, which contains the following properties for each particle.
1- scale
2- val
3- eigenvalue
4- eigenvector
5- Hessian elements
6- Spatial coordinates

Comment: At first, I convert vtk formt to vtp format.
I want to transfer this information (particle properties) from the vtp (xml structure) to 3D matrices (the same size as the CT image matrix) or tensors. The end result will be, for example, files with the following names:
scaleMatrix.nrrd , valMatrix.nrrd, eignevalueMatrix.nrrd, eignevectorTensor.nrrd and …

These files must contain matrices or tensors in which the voxels, in the particle position, have values such as scale, val, eigenvalue, and … .
I think that the coordinate system of CT images in nrrd format is the same as the coordinate system in ITK that is LPS. Is it true?
Accordingly, I used the space origin item in the header section of the CT.nrrd file to create a transform matrix.

I enter the following commands:

sn@MP:~$ ipython
Python 3.6.9 (default, Oct  8 2020, 12:12:24) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.14.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: # Load modules 
   ...: import numpy as np 
   ...: import nrrd 
   ...: import vtk  
   ...: import os                                                                                                                                                                                           

In [2]: # Load CT (nrrd file) 
   ...: filenameCT = '/home/sn/testCIP/result1/WholeLung01/wholeLung/CT_wholeLung.nrrd' 
   ...: CT, headerCT = nrrd.read(filenameCT) 
   ...: itemsHeaderCT = list(headerCT.items()) 
   ...: print("items in CT header")  
   ...: for i in range(len(itemsHeaderCT)):  
   ...:  print(i, itemsHeaderCT[i][0], itemsHeaderCT[3][1]) 
   ...:                                                                                                                                                                                                     
items in CT header
0 type [509 347 629]
1 dimension [509 347 629]
2 space [509 347 629]
3 sizes [509 347 629]
4 space directions [509 347 629]
5 kinds [509 347 629]
6 endian [509 347 629]
7 encoding [509 347 629]
8 space origin [509 347 629]

In [3]: print("items header of nnd file CT",  itemsHeaderCT[3])                                                                                                                                             
items header of nnd file CT ('sizes', array([509, 347, 629]))

In [4]: scaleMatrix = np.zeros((itemsHeaderCT[3][1]))                                                                                                                                                       

In [5]: print("matrix size scaleMatrix", scaleMatrix.shape)                                                                                                                                                 
matrix size scaleMatrix (509, 347, 629)

In [6]: print("matrix size CT:", CT.shape)                                                                                                                                                                  
matrix size CT: (509, 347, 629)

In [7]: # Load particles system (vtp file) 
   ...: filenameParticles = "/home/sn/testCIP/result1/WholeLung01/wholeLungVesselParticles.vtp"; 
   ...: readerDataVTP = vtk.vtkXMLPolyDataReader(); 
   ...: readerDataVTP.SetFileName(filenameParticles);  
   ...: readerDataVTP.Update();  
   ...: polydata = readerDataVTP.GetOutput();                                                                                                                                                               

In [8]: # Get particles coordinate 
   ...: particlesCoordinates = polydata.GetPoints();  
   ...: numberOfParticles = readerDataVTP.GetNumberOfPoints();  
   ...: print("number of particles:", numberOfParticles) 
   ...: print("Type of particles coordinates in vtp file: ", type(particlesCoordinates.GetPoint(0)))                                                                                                        
number of particles: 48425
Type of particles coordinates in vtp file:  <class 'tuple'>

In [9]: # Convert and get first particle coordinate from tuple to numpy array 
   ...: particleCoordinates = np.asarray(particlesCoordinates.GetPoint(0)) 
   ...: print("The coordinates of first particle: ", particleCoordinates)                                                                                                                                   
The coordinates of first particle:  [-146.41410828   66.66109467 -923.09509277]

In [10]: # Convert and get end particle coordinate from tuple to numpy array 
    ...: particleCoordinates = np.asarray(particlesCoordinates.GetPoint(numberOfParticles-1)) 
    ...: print("The coordinates of ",  numberOfParticles, " particle: ", particleCoordinates)                                                                                                               
The coordinates of  48425  particle:  [ -74.92162323   13.57623863 -547.72540283]

In [11]: # Get scales particles 
    ...: pointData = polydata.GetPointData() 
    ...: scaleData = pointData.GetArray(0)                                                                                                                                                                  

In [12]: # Get number of particles 
    ...: print("The number of particles based on scale: ", scaleData.GetNumberOfTuples())                                                                                                                   
The number of particles based on scale:  48425

In [13]: # Get the scale of first particles 
    ...: scaleParticle = scaleData.GetComponent(0,0)                                                                                                                                                        

In [14]: print("The scale of first particles: ", scaleParticle)                                                                                                                                             
The scale of first particles:  1.5849934816360474

In [15]: # Get the scale of 273 particle 
    ...: scaleParticle = scaleData.GetComponent(273,0) 
    ...: print("The scale of 273 particle: ", scaleParticle)                                                                                                                                                
The scale of 273 particle:  1.9540350437164307

In [16]: # Create scale matrix 
    ...: scaleMatrix = np.zeros((itemsHeaderCT[3][1])) 
    ...: print("The size of scale matrix: ", scaleMatrix.shape)                                                                                                                                             
The size of scale matrix:  (509, 347, 629)

In [17]: # Get space origin item in header nrrd CT file for creating transform matrix 
    ...: spaceOrigin = np.array([itemsHeaderCT[8][1][0],itemsHeaderCT[8][1][1] ,itemsHeaderCT[8][1][2]]) 
    ...: rowIndex = np.int(np.round(np.absolute(spaceOrigin[0]))) 
    ...: columnIndex = np.int(np.round(np.absolute(spaceOrigin[1]))) 
    ...: sliceIndex = np.int(np.round(np.absolute(spaceOrigin[2])))                                                                                                                                         

In [18]: # Create Transform matrix for converting the particle coordinates to voxel index in scale matrix 
    ...: transferLat, transferVert, transferLong = ((1, 0, 0, columnIndex), (0, 1, 0, rowIndex), (0, 0, 1, sliceIndex)) 
    ...: transformMatrix = np.array([transferLat, transferVert, transferLong]) 
    ...: print("Transfer Matrix: ", '\n', transformMatrix)                                                                                                                                                  
Transfer Matrix:  
 [[  1   0   0 118]
 [  0   1   0 190]
 [  0   0   1 925]]

In [19]: # Set voxel index 
    ...: indexParticle = 1 
    ...: for indexParticle in range(numberOfParticles): 
    ...:  particleCoordsTmp = np.asarray(particlesCoordinates.GetPoint(indexParticle)) 
    ...:  particleCoordinates = np.array([[particleCoordsTmp[0], particleCoordsTmp[1], particleCoordsTmp[2], 1]]).T 
    ...:  voxelIndex = (np.absolute(np.round(transformMatrix.dot(particleCoordinates)))).astype(int) 
    ...:  scaleMatrix[np.int(voxelIndex[2,0])][np.int(voxelIndex[0,0])][np.int(voxelIndex[1,0])] = scaleData.GetComponent(indexParticle, 0) 
    ...:                                                                                                                                                                                                    

In [20]: # Save scale matrix 
    ...: nrrd.write('scaleMatrix.nrrd', scaleMatrix, headerCT)                                                                                                                                              

In [21]: exit                                                                                                                                                                                               
sn@MP:~$ 

After executing these commands, I noticed that the scale property of all particles has not been transferred into the scaleMatrix. Also, its directions are not the same as CT.

If possible, please guide me.
Best regards.
Shahrokh.

Does the VTK file contain a surface mesh? If yes, then it would be very sparse to put that into a volume (you would have about 99% of your voxels undefined). Why would you like to store point data in a volume? Can you upload an example vtk file somewhere and post the link here?

Hello Dear Andras

At first, I should mention that the CIP outputs includes the following files:
1- A vtk file containing the particles system (for example wholeLungVesselParticles.vtk),
2- nrrd files containing val, eigenvalues, eigenvectors, Hessian elements and … with the following names:
val.nrrd, hmode.nrrd, hess.nrrd, heval[0-2].nrrd and hevec[0-2].nrrd

As mentioned in the previous message, I converted the particles system file to vtp format by using MIRTK. Then I executed the mentioned commands.

About this question that “Does the VTK file contain a surface mesh?”, I did not find the word mesh in the file of particles system (wholeLungVesselParticles.vtk).

Also, about this question that “Why would you like to store point data in a volume?”, I have to say that I want to give this information to a deep learning algorithm (CNN) in structures such as matrix or tensor.

Also I must mention that I want to use the following features to classify pulmonary vessels into healthy and diseased groups.

Features:
1- val(HU unit in the location of particle sampled),
2- scale( vessel size avaiable at the file of wholeLungVesselParticles.vtk)
3- eigenvectors (hevec[0-2])
4- eigenvalues (heval[0-2])
5- hess (Hessian matrix)

Comments: I believe all the information contained in output files (val.nrrd, hmode.nrrd, hess.nrrd, heval[0-2].nrrd and hevec[0-2].nrrd) is inculded in the vtk file of particles system (wholeLungVesselParticles.vtk).

I send the download link of the following files with WeTransfer:
wholeLungVesselParticles.vtk
hmode.nrrd
val.nrrd
hess.nrrd
heval0.nrrd
heval1.nrrd
heval2.nrrd
hevec0.nrrd
hevec1.nrrd
hevec2.nrrd
hmode.nrrd

I’m so glad that you guide me doing it.
Best regards.
Shahrokh.

Hello Dear Andras

I wanted to inform that the problem was solved with the following programs.

#Load modules
import numpy as np
import nrrd
import vtk
import os

#Load CT (nrrd file)
filenameCT = ‘/home/sn/testCIP/result1/WholeLung01/wholeLung/CT_wholeLung.nrrd’
CT, headerCT = nrrd.read(filenameCT)
itemsHeaderCT = list(headerCT.items())
print(“items in CT header”,’\n’)
for i in range(len(itemsHeaderCT)):
print(i, itemsHeaderCT[i][0], itemsHeaderCT[3][1])
print(’\n’)
print(“items header of nnd file CT”, itemsHeaderCT[3], ‘\n’)
scaleMatrix = np.zeros((itemsHeaderCT[3][1]))
print(“matrix size scaleMatrix”, scaleMatrix.shape, ‘\n’)
print(“matrix size CT:”, CT.shape, ‘\n’)

#Load particles system (vtp file)
filenameParticles = “/home/sn/testCIP/result1/WholeLung01/wholeLungVesselParticles.vtp”;
readerDataVTP = vtk.vtkXMLPolyDataReader();
readerDataVTP.SetFileName(filenameParticles);
readerDataVTP.Update();
polydata = readerDataVTP.GetOutput();

#Get particles coordinate
particlesCoordinates = polydata.GetPoints();
numberOfParticles = readerDataVTP.GetNumberOfPoints();
print(“number of particles:”, numberOfParticles, ‘\n’)
print("Type of particles coordinates in vtp file: ", type(particlesCoordinates.GetPoint(0)),’\n’)
#Convert and get first particle coordinate from tuple to numpy array
particleCoordinates = np.asarray(particlesCoordinates.GetPoint(0))
print("The coordinates of first particle: ", particleCoordinates)
#Convert and get end particle coordinate from tuple to numpy array
particleCoordinates = np.asarray(particlesCoordinates.GetPoint(numberOfParticles-1))
print("The coordinates of ", numberOfParticles, " particle: ", particleCoordinates)

#Get scales particles
pointData = polydata.GetPointData()
scaleData = pointData.GetArray(0)
#Get number of particles
print("The number of particles based on scale: ", scaleData.GetNumberOfTuples())
#Get the scale of first particles
scaleParticle = scaleData.GetComponent(0,0)
print("The scale of first particles: ", scaleParticle)
#Get the scale of 273 particle
scaleParticle = scaleData.GetComponent(273,0)
print("The scale of 273 particle: ", scaleParticle)

#Create scale matrix
scaleMatrix = np.zeros([itemsHeaderCT[3][1][0], itemsHeaderCT[3][1][1], itemsHeaderCT[3][1][2]])
print("The size of scale matrix: ", scaleMatrix.shape)

#Get space origin item in header nrrd CT file for creating transform matrix
spaceOrigin = np.array([itemsHeaderCT[8][1][0],itemsHeaderCT[8][1][1] ,itemsHeaderCT[8][1][2]])
rowIndex = np.int(np.round(np.absolute(spaceOrigin[0])))
columnIndex = np.int(np.round(np.absolute(spaceOrigin[1])))
sliceIndex = np.int(np.round(np.absolute(spaceOrigin[2])))

#Create Transform matrix for converting the particle coordinates to voxel index in scale matrix
transferLat, transferVert, transferLong = ((1, 0, 0, rowIndex), (0, 1, 0, columnIndex), (0, 0, 1, sliceIndex))
transformMatrix = np.array([transferLat, transferVert, transferLong])
print("Transfer Matrix: ", ‘\n’, transformMatrix)

#Set voxel index
indexParticle = 1
for indexParticle in range(numberOfParticles):
particleCoordsTmp = np.asarray(particlesCoordinates.GetPoint(indexParticle))
particleCoordinates = np.array([[particleCoordsTmp[0], particleCoordsTmp[1], particleCoordsTmp[2], 1]]).T
voxelIndex = np.floor(transformMatrix.dot(particleCoordinates)/0.6250495910644531).astype(int)
#print("Particle Coordinate: ", particleCoordsTmp, " Voxel Index: ", voxelIndex.T,’\n’)
#print("Voxel Index: ", voxelIndex.T)
scaleMatrix[np.int(voxelIndex[0,0])][np.int(voxelIndex[1,0])][np.int(voxelIndex[2,0])] = scaleData.GetComponent(indexParticle, 0)

nrrd.write(‘scaleMatrix.nrrd’, scaleMatrix, headerCT)

The result is shown in the following figure.

Dear Andras I’m sorry, but I’ve got it right now. You said in the previous message that “Does the VTK file contain a surface mesh? If yes, then it would be very sparse to put that into a volume (you would have about 99% of your voxels undefined).

At now I realized that maybe I should work with projecting points on a 2D plane that looks like the following figure.
This is done by selecting Projection mode in Model module.

What do you suggest me to do it (Project 3D model to 2D plane, for example a 2D matrix)?
Please guide me.
Shahrokh

Since you have all your attributes defined at vessel points, it may be more appropriate to run the deep learning on arrays created from these attributes directly (instead of painting into a volume). You could create an attribute array for each vessel point from attributes of that point and nearby points.

I would recommend to do some literature search to see how others classify trees or point sets and do a lot of experiments to see what works.

Dear Andras

Thank you very much. As you guide me, I want to use these properties (24 features) in classification by creating an attribute array for each case (number of rows equal to the number of particles sampled and number of columns equal to the number of particle properties).

Best regards.
Shahrokh

1 Like