1

Starting from an image I did some processing (like thresholding) and I obtained its representation as UnstructuredGrid using VTK and PyVista. I would like to create an array of shape (n, 3) filled with x, y, z coordinates associated with a specific y coordinate of which I know the value, but not the position of corresponding cells in the UnstructuredGrid.

I didn't understand too well what an UnstructuredGrid is so I don't know how to access and extract specific point values and coordinates. My goal is to create a list of coordinates of the front face of the image, that will be the input for a ray tracing algorithm.

MIM
  • 11
  • 2
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Nov 14 '22 at 08:33
  • It's not clear what you're asking exactly. Specifically, "associated to a specific y point" and "list of [shape] nx3" seem a bit contradictory to me. Do you mean that you want to find every remaining pixel in your image with a given y coordinate? In other words, would the middle column of that (n, 3)-shaped coordinate array be all the same value you chose? [Edit]ing your question with a small runnable example would probably help explain your point (e.g. take [a puppy](https://docs.pyvista.org/api/examples/_autosummary/pyvista.examples.downloads.download_puppy.html), threshold it and explain). – Andras Deak -- Слава Україні Nov 14 '22 at 22:20
  • @AndrasDeak--СлаваУкраїні yes, I have a structure like a box that is represent by a data of type UnstructuredGrid with the pixel values of the starting image and from this UnstructuredGrid I want to extract all the x and z coordinates associated to a y coordinates equal to the minimum of the UnstructuredGrid. Because with this coordinates I want to create the origins vector for implementing a Ray Tracing algorithm. In summary I want to extract all the coordinates of the front face of my rectangular box. I hope this will be more clear – MIM Nov 16 '22 at 14:12
  • @MIM I've taken a shot at clarifying your question. Please check my edit and feel free to edit further if you disagree with any of my changes. – Andras Deak -- Слава Україні Nov 16 '22 at 22:41

1 Answers1

0

Most of the tooling you need is the UnstructuredGrid.extract_cells() filter, which lets you select cells based on a boolean mask array or integer indices. Building such a mask is fairly easy if you compare the y coordinates of cell centers with the specific value you are looking for:

import pyvista as pv
from pyvista.examples import download_puppy

# example data
mesh = download_puppy().threshold(80)
# example point coordinates: use middle cell's center
mesh_cell_centers = mesh.cell_centers()
x0, y0, z0 = mesh_cell_centers.points[mesh.n_cells // 2, :]

# plot example mesh
def plot_puppy():
    """Helper function to plot puppy twice."""
    pl = pv.Plotter()
    pl.background_color = 'lightblue'
    pl.add_mesh(mesh, scalars='JPEGImage', rgb=True)
    pl.add_bounding_box()
    pl.camera.tight(padding=0.1)
    return pl
plotter = plot_puppy()
plotter.show()

# extract cells with center y coordinate same as y0
indices_to_keep = mesh_cell_centers.points[:, 1] == y0  # boolean mask
# for inexact matching we could use np.isclose(mesh_cell_centers.points[:, 1], y0)
subset = mesh.extract_cells(indices_to_keep)

# visualize extracted cell centers with points
plotter = plot_puppy()
plotter.add_points(subset, color='red', render_points_as_spheres=True)
plotter.show()

The x0, y0, z0 in my example are the coordinates of the "middle" cell left after thresholding, in your actual use case you need something like y0 = mesh_cell_centers.points[:, 1].min() if you want to match the cells with the lowest y coordinate. In any case calling cell_centers() is an important step to obtain the cell coordinates as points of an auxiliary mesh.

Here's what the thresholded puppy looks like:

example puppy mesh, transparent in patches due to thresholding

The thresholding turns the original UniformGrid image into an UnstructuredGrid of scattered pixels. Starting from a UniformGrid is also useful for matching y coordinates exactly using ==, but even without this we could use np.isclose for approximate matching of float values (as I pointed out in a comment).

Here's the second image, where red spheres are superimposed on the puppy at positions that were matched in the mesh subset (another UnstructuredGrid):

patchy puppy with red spheres superimposed along a line, corresponding to a constant y coordinate of pixels, as expected

This agrees with our expectations: we only see cells with a specific y coordinate, and we only see cells where the puppy is not transparent.

Since you need the coordinates of the corresponding cells, you can just use subset.cell_centers().points for an (n, 3)-shaped array, or pick out the x and z coordinates with subset.cell_centers().points[:, [0, 2]] with shape (n, 2).