I have to generate a 2d mesh in a format compatible with optimesh, in order to refine it with the algorithms included in that library, (in particular Centroidal Voronoi tesselation smoothing). I'm starting from a set of unordered points, so I'm trying to understand which is the easiest chain of tools to do the job.I have no familiarity at all with geometry processing, so forgive me if my questions are stupid.
I found a lot of libraries to process a mesh from a file in a huge variety of format, but I'm missing how to generate it from points.
I've seen that with scipy I can get a triangulation, but the object returning from scipy, can't be fed directly to optimesh.
So, my problem now is basically something like this:
import numpy as np
from scipy.spatial import Delaunay,delaunay_plot_2d
points = np.random.random((100,2))
delaun = Delaunay(points)
#Magic code that I wish
delaun.to_meshfile('meshfile.xxx')
#
with a file format that i can process later with optimesh
optimesh author here. Your delaun object has delaun.points and delaun.simplices. Those can be fed into optimesh:
import numpy as np
from scipy.spatial import Delaunay, delaunay_plot_2d
import optimesh
points = np.random.random((100, 2))
delaun = Delaunay(points)
points, cells = optimesh.cvt.quasi_newton_uniform_blocks(
delaun.points, delaun.simplices, tol=1.0e-5, max_num_steps=100
)
If you really want to store them in a file, check out meshio.
Related
I'm trying to import a 3D cylindrical CFD mesh into Itasca PFC7-3D software from Gmsh using Fipy. The mesh created in Gmsh environment is fully structured(hexahedron cells). However when I tried to import the mesh into Itasca I realized it is imported in unstructured way (tetrahedron). As I don't know much about Fipy, my first guess is that maybe node-ordering convention differs in Itasca and Fipy. (Fipy version 3.4.3, python version 3.6, PFC3D version 7, Gmsh version 4.11.1). Any helps is wholeheartedly appreciated. This is what I built in Gmsh Gmsh mesh. As you see mesh structure is fully Hexa. Itasca PFC is supplied with a distribution of Python 3.6 called ipython that is specifically configured for use with Itasca software. So I tried to use Fipy in order to import my Gmsh mesh into Itasca PFC. But mesh imports distorted and fully tetra. This is the output element plot in Itasca PFC Itasca PFC mesh
I guessed mayby removing non-hexa elements in .msh file will do the trick(because Gmsh implements meshing first in 1D then in 2D and finally in 3D to create a 3D mesh and msh file contains all those information) but it never did. Also I tried to comprehend the node-ordering convention in both ways and applied changes in my python code but I failed.
Here's the python code piece by which I tried to import Gmsh mesh into Itasca PFC using Fipy 3.4.3 :
import fipy as fp
import numpy as np
from itasca import cfdarray as ca
class DarcyFlowSolution(object):
def __init__(self):
self.mesh = fp.meshes.gmshMesh.Gmsh3D(r"C:\Users\lenovo\Documents\Itasca\pfc3d700\My Projects\c6") #.msh file directory
ca.create_mesh(self.mesh.vertexCoords.T,
self.mesh._cellVertexIDs.T[:,(0,2,3,1,4,6,7,5)].astype(np.int64))
#itasca.cfdarray.create_mesh(nodes: array float{nnodes, 3}, elements: array int{nelem, 8}) → None.
#Create a cfd mesh. The indices in the array elem should index the node locations in the array node. Counting begins at 0.
Plus this is the node-ordering convention in PFC which is provided in Itasca documentation:
node-ordering convention in PFC
I don't believe that you are getting tets. Instead, I think there are two issues:
the nodes you pass to create_mesh() describe two quadrilaterals for each cell, parallel to the yz plane, whereas Itasca and Gmsh both want the two faces of a hexahedron to be parallel to the xy plane.
_cellVertexIDs does not guarantee any particular ordering and I find that different cells can be mirrored and twisted with respect to each other (FiPy doesn't use _cellVertexIDs for anything other than testing some known meshes, so we don't care that the ordering isn't consistent). There is a separate _orderedCellVertexIDs property that preserves the ordering of Gmsh elements.
With the caveat that I do not have Itasca and have never used it, I think you should try
ca.create_mesh(self.mesh.vertexCoords.T,
self.mesh._orderedCellVertexIDs.T.astype(np.int64))
Note, this still might not work for you because the node-ordering convention in PFC image that you shared looks like a left-hand coordinate system to me which is... odd... Gmsh and FiPy both operate in a right-hand coordinate system.
I diagnosed with a simple two element mesh generated with
mesh = fp.GmshGrid3D(dx=5, dy=4, dz=3, nx=2, ny=1, nz=1)
If the above doesn't work, please provide your .msh file and I'll try to do more diagnostics.
I'm having a weird problem using the numpy fft class. I have the following bit of test code:
import numpy as np
import scipy.io.wavfile
import matplotlib.pyplot as plt
fs, a = scipy.io.wavfile.read('test.wav') # import audio file
spectrum = np.fft.fft(a) # create spectrum
b = np.real(np.fft.ifft(spectrum)) # reconstruct signal
# Print power of original and output signal
print(np.average(a**2))
print(np.average(b**2))
It outputs:
1497.887578558565
4397203.934254291
As expected for these values, the output is much louder than the input. The documentation for numpy.fft.ifft states:
"This function computes the inverse of the one-dimensional n-point discrete Fourier transform computed by fft. In other words, ifft(fft(a)) == a to within numerical accuracy."
Thus the signal should be nearly identical. Yet they are obviously not.
What am I doing wrong here?
Okay I managed to find the solution myself in the end.
The problem arises because the output of wavfile.read is an integer array. For some reason, the fft function handles integers in a different manner than floats. The problem is solved by typecasting a to an np.float64 type.
Why this happens is still not quite clear to me though.
Im new to medical image processing. how can i convert 3D DICOM medical images to numerical matrix format using either python or c++?
Another option, if you really want "3D" dicom image support (ie CT/MR/NM/PET 3d series - as opposed to purely 2D image handling) and you want do anything really 3d related and/or more complex, you might want to check out simple ITK.
That gives you very powerful true 3d handling and is fast (it's wrapped around complied C). It includes, for example, full 3D image registration and various filters/tools etc.
It can read an entire series at once and automatically create a fully spatially aware 3D numpy array for you (ie it takes care of processing all the dicom 3D spatial orientation/spacing etc tags for you)
However, because it's a lot more powerful than pydicom, it also has a much steeper learning curve - but does have many examples and online jupyter notebook tutorials.
...so, depending on your needs it might be good for you. However, if you only really want basic 2d image-at-a-time type processing, pydicom is the way to go.
You can use pydicom package in python. You can install it in python by:
pip install pydicom
Here is a simple example of reading DICOM images and converting to numpy array:
import os
import pydicom
import numpy as np
dicom_dir = your_dicom_folder_of_slices
file_names = os.listdir(dicom_dir)
file_names.sort()
dicom_data = []
for name in file_names:
path = os.path.join(dicom_dir, name)
dicom_data.append(pydicom.read_file(path))
array = [data.pixel_array for data in dicom_data]
array = np.stack(array, axis=-1) # or 0 if 'channel_first'
Here is a detailed example.
I prefer using SimpleElastix for medical image processing. it has many methods for segmentations and many other helpful methods. it is available in both python and C++. In my experience SimpleElastix handled DICOMS and niftis better than other Packages.
I'm working on a 3D reconstruction system and want to generate a triangular mesh from the registered point cloud data using Python 3. My objects are not convex, so the marching cubes algorithm seems to be the solution.
I prefer to use an existing implementation of such method, so I tried scikit-image and Open3d but both the APIs do not accept raw point clouds as input (note that I'm not expert of those libraries). My attempts to convert my data failed and I'm running out of ideas since the documentation does not clarify the input format of the functions.
These are my desired snippets where pcd_to_volume is what I need.
scikit-image
import numpy as np
from skimage.measure import marching_cubes_lewiner
N = 10000
pcd = np.random.rand(N,3)
def pcd_to_volume(pcd, voxel_size):
#TODO
volume = pcd_to_volume(pcd, voxel_size=0.05)
verts, faces, normals, values = marching_cubes_lewiner(volume, 0)
open3d
import numpy as np
import open3d
N = 10000
pcd = np.random.rand(N,3)
def pcd_to_volume(pcd, voxel_size):
#TODO
volume = pcd_to_volume(pcd, voxel_size=0.05)
mesh = volume.extract_triangle_mesh()
I'm not able to find a way to properly write the pcd_to_volume function. I do not prefer a library over the other, so both the solutions are fine to me.
Do you have any suggestions to properly convert my data? A point cloud is a Nx3 matrix where dtype=float.
Do you know another implementation [of the marching cube algorithm] that works on raw point cloud data? I would prefer libraries like scikit and open3d, but I will also take into account github projects.
Do you know another implementation [of the marching cube algorithm] that works on raw point cloud data?
Hoppe's paper Surface reconstruction from unorganized points might contain the information you needed and it's open sourced.
And latest Open3D seems to be containing surface reconstruction algorithms like alphaShape, ballPivoting and PoissonReconstruction.
From what I know, marching cubes is usually used for extracting a polygonal mesh of an isosurface from a three-dimensional discrete scalar field (that's what you mean by volume). The algorithm does not work on raw point cloud data.
Hoppe's algorithm works by first generating a signed distance function field (a SDF volume), and then passing it to marching cubes. This can be seen as an implementation to you pcd_to_volume and it's not the only way!
If the raw point cloud is all you have, then the situation is a little bit constrained. As you might see, the Poisson reconstruction and Screened Poisson reconstruction algorithm both implement pcd_to_volume in their own way (they are highly related). However, they needs additional point normal information, and the normals have to be consistently oriented. (For consistent orientation you can read this question).
While some Delaunay based algorithm (they do not use marching cubes) like alphaShape and this may not need point normals as input, for surfaces with complex topology, it's hard to get a satisfactory result due to orientation problem. And the graph cuts method can use visibility information to solve that.
Having said that, if your data comes from depth images, you will usually have visibility information. And you can use TSDF to build a good surface mesh. Open3D have already implemented that.
In python 3.6 I have imported a netCDF4 file containing global precipitation values. I have also imported a shapefile which contains the shape for the Colorado River basin. My goal is to be able to read/extract precipitation data only within my shapefile. I have looked up multiple examples but none have really helped.
Here is my code so far:
from netCDF4 import Dataset
import numpy as np
import geopandas as gpd
nc = Dataset('filename.nc')
long = nc.variables['lon'][:]
lati = nc.variables['lat'][:]
rainfall = nc.variables['precip'][:]
shapefile=gpd.read_file('filename.shp')
There are no error messages on the code above.
Oh, look, hydrologist in the house! ;)
Well, so far you haven't done much with your code, all you did was read files into memory.
When I was trying to perform the same analysis (only with grib files), I found a great Python library for exactly such purpose, called RasterStats.
It supports working with ndarray raster objects as well as most of the GDAL supported raster filetypes (must be netCDF also!), and it generates exactly the thing you want.
For more, see a very neat manual and let me know if you get stuck somewhere!