Skip to content

Conversation

@panovr
Copy link
Contributor

@panovr panovr commented Feb 24, 2017

This pull request is to port the Hough transform from ImgLib1 to ImgLib2, and also see this issue: imagej/imagej-ops#465

@hanslovsky
Copy link
Member

Just as a note: The link to issue 465 is broken in your comment. I can c&p the text though.

@panovr
Copy link
Contributor Author

panovr commented Feb 24, 2017

@hanslovsky fixed

pom.xml Outdated
</dependency>
<dependency>
<groupId>net.imglib2</groupId>
<artifactId>imglib2-algorithm-gpl</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a problem. The imglib2-algorithm-gpl component must not be a dependency here, both for legal reasons, as well as logistical/organizational ones.

pom.xml Outdated
</dependency>
<dependency>
<groupId>net.imglib2</groupId>
<artifactId>imglib2-ij</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a problem. We must not depend on ImageJ 1.x here.

pom.xml Outdated
<!-- SCIFIO dependencies -->
<dependency>
<groupId>io.scif</groupId>
<artifactId>scifio</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must not depend on SCIFIO here. The imglib2-algorithm component should not need to read/write image formats.

/.settings/
/target/

# IntelliJ
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a separate commit, with message like "Ignore IntelliJ metadata files"

*
* rho = y * sin(theta) + x * cos(theta)
* @Override
*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add yourself, as well as the original author(s), as @authors here.

* For a given point, then, votes are placed along the curve
*
* rho = y * sin(theta) + x * cos(theta)
* @Override
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @Override annotation makes no sense here.

private final double[] theta;
private ArrayList<double[]> rtPeaks;

final private static float computeLength(final long[] position) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply the ImgLib2 style formatting to this class, so formatting is consistent with the rest of ImgLib2.

@ctrueden
Copy link
Member

Thanks so much for working on this! It is looking really, really good!

Three main concerns:

  1. Extra dependencies are undesirable. I did not see where you actually need them? Probably they can just be removed?
  2. Style formatting would be nice to match with the rest of ImgLib2. There are Eclipse formatting rules for this, but maybe you want to make IntelliJ version of them and commit it to ImgLib2 repository, to help others who use IntelliJ?
  3. We need unit tests.

If you can address the above three things, I am happy.

@tinevez
Copy link
Contributor

tinevez commented Feb 24, 2017

I notice that this PR covers hough line transform. Are there plans for hough circle transform?

@panovr
Copy link
Contributor Author

panovr commented Feb 24, 2017

@ctrueden I really appreciate for the detailed code review, thanks!

FIX:

  • the undesirable dependencies exist because I write a test class for validating. I should delete these.
  • the imglib2-algorithm-gpl is need for the PickImagePeaks class in HoughTransform.java at this line
  • I format code using default IntelliJ code format, and I will re-format code to ImgLib2 style.
  • I will complement unit tests. Any example I can follow? @ctrueden

TODO:

  • Add a method for generate lines coordinates based on vote images
  • Add hough circle transform or need others contribution @tinevez

HELP:

  • I still don't know how to use the method public void setSuppression( final double[] r ) in class PickImagePeaks.java of file PickImagePeaks after the vote space image has been computed if I want to invoke the method public ArrayList< long[] > getPeakList() at this line @tinevez

@ctrueden
Copy link
Member

the imglib2-algorithm-gpl is need for the PickImagePeaks class

OK. If the implementation would be more complicated without using this class, then I propose to add these Hough classes instead to imglib2-algorithm-gpl, to avoid circular dependency, and to have correct, legal licensing.

I will complement unit tests. Any example I can follow?

There are tons of unit tests across many components. We use JUnit. You could look at e.g. DilationTest in this repository to see how Jean-Yves tests the morphological dilate operation.

@hanslovsky
Copy link
Member

What exactly is the PickImagePeaks class used for in this case? Is it simply to find local extrema? You could use LocalExtrema instead.

@ctrueden
Copy link
Member

ctrueden commented Mar 8, 2017

@panovr Did you try with LocalExtrema yet?

@panovr panovr force-pushed the hough-transform branch from 3781e52 to 31f7117 Compare March 9, 2017 15:45
@panovr
Copy link
Contributor Author

panovr commented Mar 9, 2017

@hanslovsky @ctrueden I will investigate LocalExtrema later.

@tinevez
Copy link
Contributor

tinevez commented Apr 6, 2017

I am taking care of the Hough circle transform.

@ctrueden
Copy link
Member

ctrueden commented Apr 6, 2017

@tinevez OK, thank you very much!

@imagejan
Copy link
Member

imagejan commented Jun 6, 2017

@tinevez are you planning to migrate your work in https://github.com/tinevez/CircleSkinner/tree/master/src/main/java/net/imagej/circleskinner/hough to imglib2-algorithm?

@tinevez
Copy link
Contributor

tinevez commented Jun 6, 2017

Yes, before end of June.

@ctrueden
Copy link
Member

@tinevez I have a new undergrad student, @gselzer, working on ImageJ Ops and ImgLib2 stuff now. If there is anything he could take off your plate relating to the Hough transform project, just let us know!

@tinevez
Copy link
Contributor

tinevez commented Jul 18, 2017

Christ I am late everywhere.
@gselzer can we chat over gitter sometime about this?

@gselzer
Copy link
Contributor

gselzer commented Sep 21, 2017

@tinevez I'm sorry that I did not see this comment before, but I am just now beginning to move onto this project and would love to chat on Gitter!

@ctrueden
Copy link
Member

ctrueden commented Nov 7, 2017

See also imagej/imagej-ops#526.

@hanslovsky
Copy link
Member

@panovr did you have a look at LocalExtrema and whether or not that could (partially) replace PickImagePeaks?

@ctrueden
Copy link
Member

@hanslovsky FYI, @panovr has moved on from LOCI (back to China, where has main project is machine learning classification and segmentation of bird species). But our student @gselzer could (will! 😉) work on completing this PR.

@hanslovsky
Copy link
Member

Thanks for the update @ctrueden

@gselzer
Copy link
Contributor

gselzer commented May 15, 2018

In general I do agree and this is what I was referring to with my more high-level test that does not look at the vote space and only checks if the correct parameters are obtained.

Ah okay now I understand what you mean by a high-level test. This is what testPickPeaks currently does; it takes the same image used in testHoughLineTransformToTarget, runs the transform and then pickLinePeaks on the resulting votespace, and then compares the resulting Points to what is expected.

Only if we can comprehend how the ground truth was generated, otherwise a future error will be rather useless. I still don't see how an appropriate example cannot be hand crafted.

I think that the point @ctrueden and I are trying to make here is that this test has less to do with assuring the correctness of the algorithm and more to do with guaranteeing reproducability. This test will fail if any math changes and as such a success from this test is a sign that an output after an update to the algorithm is the same output that would have been given before. With that being said you are right in that it is not an indicator that the algorithm is working correctly; that is what testPickPeaks is designed to do. We can change the name of this test if that would help make it more clear that reproducability is the goal.

@hanslovsky
Copy link
Member

@gselzer I still think that a hand-crafted test would do the same thing and, on top of that, would add documentation of what is being tested. But @ctrueden is an imglib2 admin and should have the last word on this.


while ( imageCursor.hasNext() )
{
double fRho;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to declare fRho and r outside the loop. Put declaration at initialization (line 393) and change r to long.

for ( int t = 0; t < nTheta; ++t )
{
fRho = Math.cos( theta[ t ] ) * imageCursor.getDoublePosition( 0 ) + Math.sin( theta[ t ] ) * imageCursor.getDoublePosition( 1 );
r = Math.round( ( float ) ( ( fRho - minRho ) / dRho ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Do not cast to float before rounding.
  • Is rounding correct? That would mean that the value of each r bin defines the center of said bin, not the min. If that is the desired behavior, ignore this second bullet point.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hanslovsky you are right about the cast. I do however think that this rounding is correct since we are using r to approximate our value of rho, meaning that we want to round up in the case that rho is closer to the r greater than it than it is to the r less than it, if that makes sense.

{
for ( int t = 0; t < nTheta; ++t )
{
fRho = Math.cos( theta[ t ] ) * imageCursor.getDoublePosition( 0 ) + Math.sin( theta[ t ] ) * imageCursor.getDoublePosition( 1 );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x and y should be cached outside loop to avoid potential virtual method call overhead:

if ( filter.test( imageCursor.get() ) )
{
	double x = imageCursor.getDoublePosition( 0 );
	double y = imageCursor.getDoublePosition( 1 );
	for () // continue as before.
}

final double minTheta = -Math.PI / 2;
final double dTheta = Math.PI / nTheta;

final double[] rho = new double[ nRho ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • double[] rho is never used, can be removed
  • double[] theta caches theta but the expensive caclulations are Math.sin( theta ) and Math.cos( theta ). Cache these instead.

gselzer added 8 commits May 16, 2018 09:08
this commit removes the unused rho[] LUT and refactors the theta[] LUT
into two different LUTs for sin(theta) and cos(theta). This refactor
speeds up later calculations
This commit changes the Predicate deciding whether to allow votespace
population from being a strictly greater-than to a
greater-than-or-equal-to comparison. This fix was made to prevent a bug
in which no threshold is provided to the algorithm and at the same time
the max value of the image is at the first index of the image. If the
comparison is not <= then all pixels will fail the Predicate, since no
pixel is greater than the max. This means that passing a value to the
algorithm is still preferable but allows more scenarios where no value
is given.
@hanslovsky
Copy link
Member

hanslovsky commented May 16, 2018

The build currently fails with JavaDoc errors. Most of those errors are unrelated and fixed in master. I locally merged with master and the only remaining JavaDoc error is this:

[ERROR] /path/to/imglib2-algorithm/src/main/java/net/imglib2/algorithm/hough/HoughTransforms.java:325: error: reference not found
[ERROR]          * vote space as well. Thus if {@link HoughTransforms#pickPeaks} is not used

This is an easy fix, just repleace pickPeaks with pickLinePeaks. To confirm that JavaDoc generation does not fail you can run mvn javadoc:javadoc (warnings can be ignored).

import net.imglib2.view.Views;

/**
* This abstract class provides some basic functionality for use with arbitrary
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documentation is not accurate anymore, should probably be something along the lines of:
This class provides static methods for the detection of lines in two-dimensional images via the Hough transform.

@hanslovsky
Copy link
Member

hanslovsky commented May 16, 2018

@gselzer Once you update

  • the JavaDoc to fix the error, and
  • my last requested change,

this looks good for a merge to me. Yours and @ctrueden's argument regarding the test case makes sense and I agree that we should leave it as is now.

@gselzer gselzer force-pushed the hough-transform branch from cba4673 to 2e8f6b8 Compare May 16, 2018 20:58
@gselzer
Copy link
Contributor

gselzer commented May 16, 2018

@hanslovsky I just fixed the error and the requested change in the most recent commit. Thanks for taking all the time and effort to get this project ready to merge!

@hanslovsky
Copy link
Member

@gselzer I looked over it once more and it seems good to me. Thank you for putting the work in and bearing with me and all my pedantic requests. I will leave this open for a little bit longer (probably until the end of the week) to see if anyone else raises concerns, and then I will merge.

Good work!

@hanslovsky
Copy link
Member

@imglib/admins What is the appropriate merge strategy? Squash and merge?

@ctrueden
Copy link
Member

@hanslovsky I personally prefer "Create a merge commit" to preserve the history, assuming each commit compiles with passing tests. Otherwise, what is the point of making clean topic branches? That said, I am not an ImgLib admin—see Governance summary—so ultimately it is up to @tpietzsch and @axtimwalde and @StephanPreibisch.

@hanslovsky
Copy link
Member

@ctrueden I was advised for my own (single-feature addition) PRs to rebase before a merge but I do not
want to make this decision here.

@ctrueden
Copy link
Member

I was advised for my own (single-feature addition) PRs to rebase before a merge

Doing that will do a fast-forward merge, which loses the fact that it was ever a branch. This is a bad thing which has caused social confusion and resentment in the past, where fingers were pointed and people were accused of "not working on a branch" even though they did at the time. I strongly encourage the ImgLib2 admins to use "Create a merge commit." This can still be combined with a rebase first, if you want the topic branch to sit on top the latest master. The goal is to avoid fast forward merges.

@hanslovsky
Copy link
Member

@ctrueden sorry for the confusion. I was advised to rebase my branch, then the PR would be merged with a commit message. That was before github had options to rebase through the web interface.

@axtimwalde
Copy link
Member

@ctrueden @hanslovsky the history of this pull request is painfully long and of limited educational value. It is certainly possible to ask @gselzer to rebase this post-fact into meaningful dissection supporting units but I also think that we all have a lot of stuff to do and this is not very helpful. I would therefore vote for squash and merge.

@ctrueden
Copy link
Member

@axtimwalde I don't see why further rebasing would be needed. The commits are already small and clean and granular. It sounds like your beef is really just that there are a lot of them but I think that helps bisectability, rather than harming it. There are no harmful intermediate states, are there? Why not just merge it?

@hanslovsky
Copy link
Member

@axtimwalde @tpietzsch Should I go ahead and squash and merge?

@axtimwalde
Copy link
Member

@hanslovsky yes.

@hanslovsky hanslovsky merged commit b19faf9 into imglib:master Aug 2, 2018
@hanslovsky
Copy link
Member

Thanks @gselzer

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants