4

Let's say I have some composite 3D graphics of various shapes. For simplicity, let's say these are just two capsules, like below:

myShapes = {CapsuleShape[{{-0.002997, 0., 0.}, {0.002997, 0., 0.}}, 2.997], 
 CapsuleShape[{{5.22693, 0.954974, 0.945536}, {5.23274, 0.956034, 
    0.946586}}, 2.997]}

Graphics3D[myShapes, ViewPoint -> Front, ViewProjection -> "Orthographic"]

enter image description here

Now, from that orthographic projection, I'd like to get a binary image of the "foreground" pixels visible from the projection, so that I can get 2D ComponentMeasurements[] (like area, circularity, etc.)

We can use Jen's function from this answer to get a black "shadow", which seems promising, but such shadow is still a Graphics3D[] object, so it does not seem very useful (but it's cool!):

enter image description here

How could I go about this?

Thanks!

Note: Ideally, the projection should respect the dimensions of the original graphics (say, the diameter/shape of the capsules), but I'm assuming the orthographic projection would take care of that(?)

user21
  • 39,710
  • 8
  • 110
  • 167
TumbiSapichu
  • 1,603
  • 8
  • 17

1 Answers1

8

Edit

If we only need image,we can use

Clear[plot, img]; 
myShapes = {CapsuleShape[{{-0.002997, 0., 
     0.}, {0.002997, 0., 0.}}, 2.997], 
  CapsuleShape[{{5.22693, 0.954974, 0.945536}, {5.23274, 0.956034, 
     0.946586}}, 2.997]}; 
plot = 
 Graphics3D[{Black, myShapes}, ViewProjection -> "Orthographic", 
  ViewPoint -> {0, -1, 0}, Boxed -> False, PlotRangePadding -> 0, 
  PlotRange -> Full];
 img = ImportString[ExportString[plot, "PNG"]]

Rasterize[plot]

enter image description here

Original

  • CapsuleShape is the BSplineSurface. It it not easy to handle.
Needs["OpenCascadeLink`"];
Needs["NDSolve`FEM`"];
myShapes = {CapsuleShape[{{-0.002997, 0., 0.}, {0.002997, 0., 0.}}, 
    2.997], CapsuleShape[{{5.22693, 0.954974, 0.945536}, {5.23274, 
      0.956034, 0.946586}}, 2.997]};
union = RegionUnion @@ myShapes;
shape = OpenCascadeShape[union];
mesh = OpenCascadeShapeSurfaceMeshToBoundaryMesh[shape, 
   "ShapeSurfaceMeshOptions" -> {"AngularDeflection" -> 0.05}];
mg = TransformedRegion[MeshRegion[mesh], 
   ScalingTransform[0, {0, 1, 0}]] // Quiet
mg // Area
dist = RegionDistance[mg];
projection = 
 ImplicitRegion[dist@{x, 0, z} <= .02, {x, z}] // DiscretizeRegion
projection // Area

55.6183

enter image description here

  • Compare with the 3D graphics.
myShapes = {CapsuleShape[{{-0.002997, 0., 0.}, {0.002997, 0., 0.}}, 
    2.997], CapsuleShape[{{5.22693, 0.954974, 0.945536}, {5.23274, 
      0.956034, 0.946586}}, 2.997]};
g = Graphics3D[
  GeometricTransformation[myShapes, ScalingTransform[0, {0, 1, 0}]], 
  ViewPoint -> Front, ViewProjection -> "Orthographic"]

Rasterize[g]

enter image description here

cvgmt
  • 72,231
  • 4
  • 75
  • 133
  • Wow, that's pretty cool. I wonder if there's a simple way to convert the "flat" 3D shapes into a binary image. In my case, I'd be using other shapes in addition to capsules (often combined in the same graphics object). But this approach is a great start, thanks! – TumbiSapichu Jul 17 '22 at 03:04
  • 1
    @TumbiSapichu image is relatively easy. For example Clear[plot, img]; myShapes = {CapsuleShape[{{-0.002997, 0., 0.}, {0.002997, 0., 0.}}, 2.997], CapsuleShape[{{5.22693, 0.954974, 0.945536}, {5.23274, 0.956034, 0.946586}}, 2.997]}; plot = Graphics3D[{Black, myShapes}, ViewProjection -> "Orthographic", ViewPoint -> {0, 1, 0}, Boxed -> False, PlotRangePadding -> 1.2, PlotRange -> Full]; img = ImportString[ExportString[plot, "PNG"]] – cvgmt Jul 17 '22 at 03:10
  • Oh, cool, that's exactly what I was trying to get at. If you write it as a response I'll accept it. – TumbiSapichu Jul 17 '22 at 03:17
  • 1
    @TumbiSapichu updated. – cvgmt Jul 17 '22 at 03:44
  • ImportString[ExportString[plot, "PNG"]] could be replaced by Rasterize – SHuisman Jan 25 '24 at 16:42
  • @SHuisman updated, thanks. – cvgmt Jan 26 '24 at 00:50