Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port kernels #48

Merged
merged 12 commits into from
Jan 20, 2015
Merged

Port kernels #48

merged 12 commits into from
Jan 20, 2015

Conversation

bnorthan
Copy link
Contributor

I've been working on porting kernel generation. At this point still looking for feedback on the design.

So far I've ported the Gaussian kernel and the Log kernel from pre-existing sources (knime and trackmate). Both of these follow the same pattern.

a) the number of dimensions is defined.
b) the radius (or sigma) is defined as a double
c) the size of each dimensions in pixels is determined by the radius

I've tried for a class hierchy that will handle these implementations but is flexible as to future variations.

@dscho
Copy link
Contributor

dscho commented Sep 17, 2014

@bnorthan if you could add to the commit message a note about the relicensing and that it was actually Jean-Yves Tinevez' code, that would be awesome! 👍 from me!

@bnorthan
Copy link
Contributor Author

Thanks @tinevez. It was definitely "ported" (copy, paste, refactor as needed, test) so I'll add a note about the relicensing. That is very helpful short term. ( Long term @dscho mentioned we should consider an ops-based gpl repository for deconvolution. I think this is a good idea. Perhaps it should be a little more general. Maybe an ops repository geared towards advanced image processing algorithms with gpl license?? ).

@bnorthan
Copy link
Contributor Author

Renamed 'FromNumDimensions' to 'NDD'. NDD stands for N-dimensional-dynamic. That means the kernel size is determined from the other inputs (for example sigma and calibrations). The reason for the distinction is that in the future there might be a different interface that takes the kernel size explicitly.

Let me know if this makes sense. And how does the rest of it look?? Thanks.

@dscho
Copy link
Contributor

dscho commented Sep 19, 2014

And how does the rest of it look?

Oh, I forgot to say that I only pointed out things that are not brilliant ;-) 👍 from my side!

@ctrueden
Copy link
Member

@bnorthan: Is this good to merge? Or is there further work that needs to happen first?

@bnorthan
Copy link
Contributor Author

It's almost there but I fixed something and added a test. I'll let you
know when it is ready.

On Fri, Sep 19, 2014 at 3:05 PM, Curtis Rueden notifications@github.com
wrote:

@bnorthan https://github.com/bnorthan: Is this good to merge? Or is
there further work that needs to happen first?


Reply to this email directly or view it on GitHub
#48 (comment).

@bnorthan
Copy link
Contributor Author

Hi Curtis - I think this should be reviewed by @dietzc when he gets back home and gets a chance (given his experience with knime filters). A couple of things have just come to mind:

a) this is an extension of create so there will be many variations of source (create from Img, create from ImgPlus, create from Type) and parameters (create from given dimensions, calculate dimension from parameters (such as sigma)). I've only implemented one case. So your plans regarding "converting" ops will be relevant here for other cases.

b) there are a few other subtle issues. For example the Gaussian code was originally written for doubles and integer types would have to be handled a bit differently.

@bnorthan bnorthan force-pushed the port_kernels branch 2 times, most recently from dd30600 to d06768b Compare September 21, 2014 21:48
@bnorthan
Copy link
Contributor Author

I changed things a bit to be compatible with the latest work done at the Hackathon.

a) interfaces now added via the Ops.list file.

b) CreateLog/GaussKernel should really extend a createimg class. I did not see a very simple AbstractCreateImg (create from type and factory then dimensions and values are determined by derived classes) so I added one. Let me know if this makes sense.

@ctrueden
Copy link
Member

@bnorthan Just waiting on review from @dietzc, correct?

@ctrueden
Copy link
Member

ctrueden commented Dec 3, 2014

@dietzc Any comments?

@dietzc
Copy link
Member

dietzc commented Dec 4, 2014

@ctrueden @bnorthan I will review this weekend! I'm sorry for the delay.

@dietzc
Copy link
Member

dietzc commented Dec 7, 2014

I like it, as it is really thin and straightforward implemented. I added some comments to the commit. Here are some additionally notes:

  • In general I would declare the fields in the ops as private whenever possible.
  • One more thing we may want to think about is if we really want to use the Gauss interface here or if a GaussKernel interface would be better? I'm a bit worried, that we may mix up the convolution with the actual creation of the kernel.
  • Maybe we can provide default values for some of the fields in the case of KernelCreation? For example, if I want to create a Gauss Kernel, the default setting is: ArrayImgFactory + Double?

Hope this helps!

@bnorthan
Copy link
Contributor Author

bnorthan commented Dec 8, 2014

Thanks for the feedback @dietzc I should have time to make the updates later this week or early next.

Log is the Laplacian of Gaussian kernel, a high pass kernel used for
edge and blob detection.
@bnorthan
Copy link
Contributor Author

@dietzc, @ctrueden

Hi Christian - I am changing the interface to support different sigmas for each dimension but I am getting an error when trying to pass in a double[] Parameter to the op.

It appears to me that it is looking for a 2D double array for the last parameter ([D [D@49d5e6da). Or perhaps I am not understanding the error message?? Have you guys had any problems passing arrays to ops?

I expected the op service to match the "CreateGaussianKernel" op. But for some reason it is reporting that op as {!INVALID}. What does that mean?? That the signature did not match?? Or something else is wrong with the op??

gausskernel(net.imglib2.img.array.ArrayImgFactory net.imglib2.img.array.ArrayImgFactory@321236f4, net.imglib2.type.numeric.real.FloatType 0.0, java.lang.Integer 2, [D [D@49d5e6da)
Candidates:
[100.0](net.imglib2.img.Img<capture of ?> output) = net.imagej.ops.convolve.kernel.create.CreateSymmetricGaussianKernel(net.imglib2.img.ImgFactory<capture of ?> fac, capture of ? outType, int numDimensions, double sigma, [D calibration?)
{!INVALID!} [0.0](net.imglib2.img.Img<capture of ?> output) = net.imagej.ops.convolve.kernel.create.CreateGaussianKernel(net.imglib2.img.ImgFactory<capture of ?> fac, capture of ? outType, [D sigma, [D calibration?)

@dietzc
Copy link
Member

dietzc commented Dec 15, 2014

it seems that you have to pass two arrays? one for the sigmas and one for the calibration?!

@bnorthan
Copy link
Contributor Author

@dietzc, @ctrueden Hi Christian - actually it wasn't that... the calibration is an optional parameter. It was something else stupid I did in the AbstractCreateKernel class. So ignore the question I had, everything is good now. Thanks for your feedback. I implemented the changes you suggested I just need to look things over a couple of more times. I'll let you know when it's finalized.

@bnorthan bnorthan force-pushed the port_kernels branch 2 times, most recently from a6c5c82 to c8fa174 Compare December 17, 2014 16:26
@bnorthan
Copy link
Contributor Author

@dietzc

Suggested changes made and tested except for this part.

Maybe we can provide default values for some of the fields in the case of KernelCreation? For >example, if I want to create a Gauss Kernel, the default setting is: ArrayImgFactory + Double?

Still thinking about the best way to do this. Are you aware of any examples using default factory and type to create an image??

@dietzc
Copy link
Member

dietzc commented Jan 5, 2015

not from my side. @ctrueden.

I think with merging these changes (especially the createImg stuff), the example in the README.md will work again. @bnorthan did you check that?

btw: great!!! :-)

@bnorthan
Copy link
Contributor Author

bnorthan commented Jan 5, 2015

@dietzc, @ctrueden

The script did not work even with my changes because I only added 'AbstractCreateDefaultImg'. If I add a new create class that derives from 'AbstractCreateDefaultImg' it works.

I called it DefaultCreateDefaultImg. I can change the name if you have a suggestion. It uses FloatType and PlanarFactory for defaults if nothing is specified. I can change this too. Any opinion on what should the defaults be??

This class is here.

https://github.com/imagej/imagej-ops/blob/port_kernels/src/main/java/net/imagej/ops/create/DefaultCreateDefaultImg.java

@dietzc
Copy link
Member

dietzc commented Jan 5, 2015

Thanks

@bnorthan I would (always) prefer to use ArrayImgFactory over PlanaImgFactory. PlanarImgs are just helpers for easier integration with ImageJ1 but is slower in the general case.

one thing which I just discovered: https://github.com/imagej/imagej-ops/blob/port_kernels/src/main/java/net/imagej/ops/create/AbstractCreateImg.java be unifided with AbstractCreateDefaultImg right? Because AbstractCreateDefaultImg doesn't implement any interface. Then you don't get in the naming hell, because DefaultCreateImg would then use FloatType and ArrayImgFactory. Do I miss something here?

@ctrueden any suggestions?

@dscho
Copy link
Contributor

dscho commented Jan 5, 2015

@dietzc you will have to consider the case where width x height x ? > 2^31. (Hint: this is something SCIFIO had to implement itself because ImgLib2 does not offer that convenience functionality.)

AbstractCreateImg is an abstract class that creates an image from a type
and factory.  The logic to determine the size and values of the image is
implemented in the derived classes.  For example CreateImgDefault (which
has been modified to derive from AbstractCreateImg) creates an empty
image from given dimensions.
Added the CreateLogKernel class.  Creates a Laplacian of Gaussian kernel
that can be used for blob detection.  Ported from:

fiji.plugin.trackmate.detection.DetectionUtilities.

Permission granted by Jean-Yves Tinevez to change license from GPL.
Creates a Gaussian Kernel.  Ported from:

org.knime.knip.core.algorithm.convolvers.filter.linear.Gaussian
Changed this class to inherit from AbstractCreateImg.  The class will
inherit the outType and the factory as optional parameters.  So images
can now be created passing only the dimensions.
KernelTest tests that the kernels run and asserts that the generated
kernel is the correct width.
@bnorthan
Copy link
Contributor Author

bnorthan commented Jan 5, 2015

@dietzc good idea, I merged the classes as you suggested.

I did not use ArrayImgFactory as the default though. There could be problems with very large images. Of course planar will have problems too if the images are very large and you would need a cell image. So it seems that eventually something is needed like "SmartImgFactory" that creates the right type based on size and available memory... but I don't see that anything like that currently exists in imglib2.

@ctrueden
Copy link
Member

ctrueden commented Jan 5, 2015

My suggestion for default would be to use a heuristic. If the requested image size is small enough, use ArrayImg; if not, use a dynamic cell image like SCIFIO does. (This would be a great thing to work on with @hinerm at the upcoming hackathon!)

And SCIFIO already has such a heuristic!

This was referenced Jan 15, 2015
@ctrueden ctrueden merged commit 7be4835 into master Jan 20, 2015
ctrueden added a commit that referenced this pull request Jan 20, 2015
This resolves PR #48.

The ReadmeExampleTest now fails, due to the merger of PR #88
(2dd2754). The fix will be to
revert commit 41ffba8.

Conflicts:
	src/main/java/net/imagej/ops/DefaultOpService.java
ctrueden added a commit that referenced this pull request Jan 20, 2015
This reverts commit 41ffba8.

The CreateImgSimple is no longer needed, because as the merger of #48,
the DefaultCreateImg now matches the simple createimg signature.
ctrueden added a commit that referenced this pull request Jan 20, 2015
The previous default createimg implementation used DoubleType,
and at the moment, various code paths only work for that case.
In particular, the README example needs a DoubleType image.

Just so that we can get the PR #48 merged right now, let's
continue using DoubleType for the very short term.

In the longer term, it will become paramount to better differentiate
between different types of Img objects at runtime, to avoid mismatched
ops and ClassCastExceptions. See issue #95.
@ctrueden ctrueden deleted the port_kernels branch January 20, 2015 20:23
@ctrueden
Copy link
Member

We had to switch the DefaultCreateImg type from float to double, but it is finally merged!

@dietzc
Copy link
Member

dietzc commented Jan 20, 2015

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants