# How to convert Graphics3D object into an Image3D object?

How does one convert a Graphics3D object into an Image3D object? E.g., start with Plot3D[x^2 - y^2, {x, -1, 1}, {y, -1, 1}].

-
Are you interested only in conversion, or creation too? – Kuba Sep 30 '13 at 21:18
@Kuba: primarily conversion. (The ref/Image3D page shows how to generate some Image3D objects from some 4D arrays of reals, and of course using Import with a data object that is already "Image3D") – murray Sep 30 '13 at 21:24
@Kuba, my question is how to obtain an Image3D object if you already have a Graphics3D object -- not how you obtain an Image3D object by starting with a function of 3 variables and picking points as in your example with UnitStep. – murray Sep 30 '13 at 21:28
Ok, just wasn't sure, let me delete this comment :) – Kuba Sep 30 '13 at 21:29

## 2 Answers

If you already have a Graphics3D object, then you can recreate an Image3D object by stacking slices of your graphics along an axis. Here's an example. We start with your object:

obj = Plot3D[x^2 - y^2, {x, -1, 1}, {y, -1, 1}]


Using the following rudimentary "slice" function, we can generate slices of the function at a given value of $x$:

slice[obj_, x_, dx_] := Show[obj, ViewPoint -> {∞, 0, 0},
PlotRange -> {{x, x + dx}, All, All}, Axes -> False, Boxed -> False]

slice[obj, 0, 0.01]


Now generate such slices for all $x$, rasterize and grab the ImageData and stack the frames:

frames = Table[ImageData@Thinning@ColorNegate@ColorConvert[#, "Grayscale"] &@
Rasterize@slice[obj, x, 0.05], {x, -1, 1, 0.01}];

Image3D[frames]


As you can see, the reconstruction is not perfect, and this arises from having to artificially sample the Graphics3D object by manipulating the plot ranges. Depending on how quickly the function changes within the chosen dx, the reconstruction could get worse/better. Note that you also need to choose the sampling such that the aspect ratio is maintained (I have only eyeballed it).

A much better reconstruction can be obtained either by generating frames using Plot (you probably can't avoid the Moiré patterns):

frames2 =
Table[ImageData@Thinning@ColorNegate@ColorConvert[#, "Grayscale"] &@
Rasterize@
Plot[x^2 - y^2, {x, -1, 1}, PlotRange -> {-1.5, 1.5},
Axes -> False, Frame -> False], {y, -1, 1, 0.01}];

Image3D[frames2]


or by directly obtaining the samples as Kuba showed.

-
that's a start. I'll hold off accepting this in the hope of finding a solution that provides a much more faithful rendering of the Grahics3D object. – murray Oct 1 '13 at 13:09
@murray Certainly. Could you perhaps explain why you want to convert to an Image3D? I'm not seeing any advantages to it over Graphics3D, but maybe I'm just being thick... – R. M. Oct 1 '13 at 13:57
@R.M. Because we can use Manipulate to inspect a 3D object slice by slice? – matheorem Jan 20 at 8:50
@matheorem, and ClipPlanes is insufficient for your needs? Honestly, going from vector to raster is quite the step down here. – J. M. Jun 26 at 20:41

You could create a region using DiscretizeGraphics and find points within a certain distance of the surface using RegionDistance

g = Normal @ Plot3D[x^2 - y^2, {x, -1, 1}, {y, -1, 1}];

f = RegionDistance @ DiscretizeGraphics @ g;

data = Array[f[{##}] &, {60, 60, 60}, {-1.1, 1.1}];

Image3D[Clip[data, {0.05, 0.05}, {1, 0}]]


-
The expression DiscretizeGraphics@g generates error message for me: "DiscretizeGraphics: The function DiscretizeGraphics is not implemented for Directive[Specularity...." – murray Jun 27 at 14:52