Bonej2 Isosurface

bonej
imagej
plugin

#1

Hello everybody,
I have huge image from which I wanted to make stl and use Isosurface in BoneJ2 for that. I’m aware that BoneJ2 is not finished yet but this post made me think that Isosurface is available in BonejJ2.
I followed Installing BoneJ2 instruction on github but couldn’t find the option calling Isosurface in BoneJ Legacy menu:


also description of Isosurface on BoneJ2 wiki and looking at the code didn’t help.
I wanted to try BoneJ2 because my file is too big to be served by Isosurface in BoneJ and hope BoneJ2 could handle it.


#2

Hi @gacekb,

This is clearly a sign I need to get onto writing user documentation for BoneJ2. The isosurface plugin is now located in Plugins>BoneJ>Surface area (near the bottom of the plug-in menu). The plug-in can create the mesh file(s) for you, but can’t display them yet. To view them you can, for example, use gmsh. Sorry for the inconvenience

Best regards,
Richard


#3

Thank you @rimadoma,
I must admit that I didn’t look carefully and didn’t notice there is ‘BoneJ’ at the bottom of the Plugins menu (in addition to ‘BoneJ Legacy’).
Now I can confirm that Isosurface plugin is working in BoneJ2 :wink:
For smaller images it works without problems. However, attempt to calculate surface area for a larger file was unsuccessful. Here is logged exception:

Summary
(Fiji Is Just) ImageJ 2.0.0-rc-68/1.52e; Java 1.8.0_172 [64-bit]; Linux 3.10.0-862.3.3.el7.x86_64; 60510MB of 175901MB (34%)
 
java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -2104393776
	at net.imagej.legacy.LegacyService.runLegacyCompatibleCommand(LegacyService.java:303)
	at net.imagej.legacy.DefaultLegacyHooks.interceptRunPlugIn(DefaultLegacyHooks.java:163)
	at ij.IJ.runPlugIn(IJ.java)
	at ij.Executer.runCommand(Executer.java:137)
	at ij.Executer.run(Executer.java:66)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -2104393776
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at net.imagej.legacy.LegacyService.runLegacyCompatibleCommand(LegacyService.java:299)
	... 5 more
Caused by: java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -2104393776
	at net.imagej.ops.thread.chunker.DefaultChunker.run(DefaultChunker.java:103)
	at org.scijava.command.CommandModule.run(CommandModule.java:199)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:944)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:156)
	at net.imagej.ops.map.MapUnaryComputers$IIToIIParallel.compute(MapUnaryComputers.java:101)
	at net.imagej.ops.map.MapUnaryComputers$IIToIIParallel.compute(MapUnaryComputers.java:87)
	at net.imagej.ops.special.chain.UHCFViaUC.compute(UHCFViaUC.java:65)
	at net.imagej.ops.special.hybrid.UnaryHybridCF.calculate(UnaryHybridCF.java:61)
	at net.imagej.ops.special.hybrid.UnaryHybridCF.run(UnaryHybridCF.java:71)
	at net.imagej.ops.special.hybrid.UnaryHybridCF.run(UnaryHybridCF.java:97)
	at org.scijava.command.CommandModule.run(CommandModule.java:199)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:944)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:156)
	at net.imagej.ops.convert.ConvertNamespace.bit(ConvertNamespace.java:132)
	at org.bonej.wrapperPlugins.wrapperUtils.Common.toBitTypeImgPlus(Common.java:43)
	at org.bonej.wrapperPlugins.IsosurfaceWrapper.run(IsosurfaceWrapper.java:116)
	at org.scijava.command.CommandModule.run(CommandModule.java:199)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:168)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:127)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:66)
	at org.scijava.thread.DefaultThreadService$3.call(DefaultThreadService.java:238)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -2104393776
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at net.imagej.ops.thread.chunker.DefaultChunker.run(DefaultChunker.java:97)
	... 24 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: -2104393776
	at net.imglib2.img.basictypeaccess.array.AbstractByteArray.getValue(AbstractByteArray.java:61)
	at net.imglib2.type.numeric.integer.GenericByteType.getByte(GenericByteType.java:127)
	at net.imglib2.type.numeric.integer.UnsignedByteType.get(UnsignedByteType.java:151)
	at net.imglib2.type.numeric.integer.UnsignedByteType.getIntegerLong(UnsignedByteType.java:168)
	at net.imagej.ops.convert.ConvertTypes$IntegerToBit.compute(ConvertTypes.java:102)
	at net.imagej.ops.convert.ConvertTypes$IntegerToBit.compute(ConvertTypes.java:89)
	at net.imagej.ops.map.Maps.map(Maps.java:297)
	at net.imagej.ops.map.MapUnaryComputers$IIToIIParallel$1.execute(MapUnaryComputers.java:106)
	at net.imagej.ops.thread.chunker.DefaultChunker$1.run(DefaultChunker.java:77)
	at org.scijava.thread.DefaultThreadService$2.run(DefaultThreadService.java:221)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	... 4 more

Previous version of BoneJ also had this problem for larger files. When I was calculating surface area for really huge files ImageJ hanged - BoneJ2 throws an exception. I hoped newer version of 3D Viewer will solve this issue. But I’m not 100% sure wheather it is this is a problem - I don’t understand everything in log above.


#4

Looks like there might be a built-in limit to the number of vertices or triangle faces that the mesher can store in memory. -2104393776 is the minimum value a Java integer can have, which means that the array storing the points got up to the maximum value (a little more than 2 billion), then wrapped around and started counting from the bottom.

You could work around this problem by downsampling your image stack first so you don’t have to make so many triangles. In BoneJ1, did you still get this problem if you used a higher value for mesh smoothing, like 6?

@kephale may have something to say about this exception too.


#5

I’m not sure it is a Mesh limit. We setup the imagej-mesh API to work with Long indices.

It looks like the issue might arise during image type conversion. I filed an issue in the BoneJ2 repo (https://github.com/bonej-org/BoneJ2/issues/106). I’m not sure if that line is the issue, but the isosurface should work without converting into an ImgPlus type.


#6

@mdoube - in BoneJ1 it wasn’t problem to calculate surface area for this file with resampling parameter equal to 6, but with resampling = 2 it hangs. Moreover, it’s no problem to calculate (even with resampling 2) surface area for image of the same size but smaller porosity and therefore smaller specific surface area. In BoneJ2 it hangs processing huge files (no matter how huge surface area) a while after asking wheather to save the stl file.


#7

Hi @gacekb,

At a quick glance it seems that the exception happens before the code gets to creating a mesh or calculating its surface area. You can follow the progress on this bug here, cheers to @kephale for creating the issue!

NB BoneJ2 surface area doesn’t yet support resampling.


#8

He is back! I hope the festivities went well :smiley:


#9

The conversion is from ImgPlus<T>, T extends RealType<T> & NativeType<T> to ImgPlus<BitType>. I’ve noticed that at least with LegacyUI an input @Parameter ImgPlus<BitType> creates trouble, namely ClassCastExceptions because the preprocessor doesn’t know how to convert numeric types like UnsignedByteType to BooleanType.

For example, the sample bat-cochlea-volume is UnsignedByteType, but for all intents and purposes it’s a binary image, and it makes sense to me to proces it as BitType. Thus the conversion. Also DefaultMarchingCubes expects T extends BooleanType<T>.


#10

Agreed. Please let me know what can be done to improve matters on the ImageJ2 core infrastructure side. One thing I think we need in Ops is for the convert namespace to have View signatures that use ImgLib2 Converters instead of copying samples. Improvements to the legacy layer here may also be warranted; CC @maarzt since IIRC he already made some improvements to the bit type logic there.


#11

@gacekb @kephale

Would you happen to have a test file for me that I could use to try to reproduce the bug?


#12

Well, it’d be nice if ConvertService had convenience methods for converting ImgPlus, i.e. conversions for the underlying Img plus copying of metadata. They could also have logic for selecting between lazy/instant conversion based on your input’s properties if that makes sense…


#13

Hi again @gacekb

Are you still experiencing the issue? Could you link me an image you used when you had the error, please? I’m having difficulties coming up with a test that would fail in the same way. @kephale, would you have a suitable test image?

Best regards,
Richard


#14

I don’t off hand. I haven’t had this issue personally. Maybe generate the image, perhaps a large 3D checkered pattern might suffice?


#15

The problem happens before the plug-in calls marching cubes, so I need to create an image too large for DefaultChunkerOp - it’s not too many vertices, it’s too many voxels. I tried naively just calling ArrayImgs.doubles(int...) with big parameters, but that naturally fails with an ArrayIndexOutOfBounds kind of error straight away, and tells me I need to try a CellImageFactory. They don’t have the same kind of convenience methods as in ArrayImgs, and I haven’t had time to look into the matter yet.


#16

Test image linked from this post
https://forum.image.sc/t/bonej-isosurface-surface-area/20560/3


#17

You can download test image from here.