# How to render a 3D tubular graphics from a 2D image path

Question: Is it possible to create a tubular 3D image like Extruding along a path using "Tube" function in mathematica for following images?

Image (1)

Image (2)

Thanks

I have been playing with previous answers: 1) Extruding along a path 2) How to extrude a 3D image from a binary 2D image 3) How to convert a 2D image into a 3D graphics?

I want to generate image like first one.

Here I tried RegionPlot3D:

I want to map the image to 3D tube which has image cross section.

• @R.M I guess ... troyerperformance.com/cgi-bin/itemimgs/Magnaflow%20Y-Pipe.jpg – Dr. belisarius Jun 12 '12 at 3:13
• @belisarius No, I think it's this – Jens Jun 12 '12 at 3:30
• To clarify the question, could you provide a Mathematica description of the curva long which you would like to extrude? Or are you maybe saying you want the curve to look like your image (1) and the cross section like your image (2)? – Jens Jun 12 '12 at 3:32
• @Jens :D you made me laugh with both commentaries. – Dr. belisarius Jun 12 '12 at 3:34
• @belisarius Yeah, I never could get the hang of this – Jens Jun 12 '12 at 3:54

The important image operation you need is called Skeletonization or Thinning. Different approaches are possible, but as far as I can see, you are interested in the medial axis of your black object.

Here is one simple recipe to create a 3D tubular medial axis from your image:

• take the image and invert the colors, because in image processing the convention is often that white is the (interesting) foreground. Operations like Thinning will often work on the white objects
• Smooth the image with a filter, because the skeleton of an image is, depending on the method you are using, often a skeleton with many small branches. This is the case for objects with rough boundaries. One way to get a smooth skeleton is to use a Gaussian filter to smooth the boundary. Pruning can be used too.
• Thinning aka morphological thinning uses an Erosion-like approach to eat from the outside of the object until there is only a one-pixel thick skeleton
• Position can then be used to extract, where to pixel positions of the skeleton is
• FindCurvedPath helps to find the single line-strips and to sort pixel position in a way that you can move along them.

Using this and keeping in mind that (1) the pixel-matrix has a reversed y-axes compared to the usual Cartesian coordinate system and (2) that Position gives $\{y,x\}$ pairs as result the following code should help you

binimg = ColorNegate[
ColorConvert[Import["http://i.stack.imgur.com/C1skp.png"],
"Grayscale"]];
skeleton3d = (Function[path, Part[#, path]] /@ FindCurvePath[#]) &[
Position[
Transpose@
Reverse@ImageData[
Thinning[Binarize[GaussianFilter[binimg, 10]]], "Bit"],
1]] /. {x_Integer, y_Integer} :> {x, y, 0};
Block[{nx, ny, tex = Texture[binimg]},
{nx, ny} = ImageDimensions[binimg];
Graphics3D[{
Opacity[0.5],
tex,
Polygon[{{0, 0, 0}, {nx, 0, 0}, {nx, ny, 0}, {0, ny, 0}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}],
Red, Opacity[1],
Tube[skeleton3d, 4]}, Boxed -> False]
]


## Update: Is it possible to map the cross-section of image.

I hope I got this right: You would like to have not a tube of constant thickness but it should vary so that would fill the illustration of your original image in my first graphic above.

This is possible to some degree. What you could do is to take additionally the DistanceTransform of your image into account. This gives at least an approximation of the tube-radii you need.

Bad news is, that Tube does not work with so many points and big radii very well, so that the final tube looks awful. Here you could use many intersecting spheres

binimg = Binarize@
ColorNegate[
ColorConvert[Import["http://i.stack.imgur.com/C1skp.png"],
"Grayscale"]];

Block[{
tex = Texture[Image[Reverse@Transpose@ImageData[binimg]]],
skel = ImageData[Pruning[Thinning[binimg], 20]],
dist = ImageData[DistanceTransform[binimg]],
},
{nx, ny} = ImageDimensions[binimg];
skelCoords = (Function[path, Part[#, path]] /@ FindCurvePath[#]) &[
Position[skel, 1]];
Map[Function[{skelpos}, {Append[skelpos, 0],
Part[dist, Sequence @@ skelpos]}], skelCoords, {2}];

Graphics3D[{Opacity[.5], tex, Opacity[1],
Polygon[{{0, 0, 0}, {ny, 0, 0}, {ny, nx, 0}, {0, nx, 0}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}],
Red, Apply[Sphere, skelCoordsWithRadii, {2}]}, Boxed -> False]

]


• I burst out laughing when I got to the bottom of your post. +1 – Mr.Wizard Jun 12 '12 at 19:46
• Hilarious, dude´ (-- Artemis Fowl, The Eternity Code) – Yves Klett Jun 12 '12 at 22:17
• @user1362 In the final Graphics3D[{...},..] remove everything from the curly braces but the part with Apply[Sphere...] – halirutan Jun 13 '12 at 1:45
• @user1362 If you smooth your image before extracting the skeleton, the medial line too becomes more smooth. Maybe for the single parts of your skeleton you can then use Tube which can with CapForm[None]` be declared to be open. Nevertheless, where the branches come together, your graphic will look awful. – halirutan Jun 13 '12 at 8:57