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, skelCoords, skelCoordsWithRadii
},
{nx, ny} = ImageDimensions[binimg];
skelCoords = (Function[path, Part[#, path]] /@ FindCurvePath[#]) &[
Position[skel, 1]];
skelCoordsWithRadii =
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]
]


