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

Removed normal related accessors and types from EuclideanClusterComparator #1542

Merged
merged 3 commits into from
Nov 3, 2017

Conversation

SergioRAgostinho
Copy link
Member

@SergioRAgostinho SergioRAgostinho commented Feb 18, 2016

Edit: The description below can be considered deprecated. Please jump into #1542 (comment)

Addresses #1514. If the normals are specified, it uses the planar equation for performing the comparison. If not it defaults to the old behaviour.

I'm starting the PR, but it still needs some discussion because there are things I'm not fully sure.

In the original comment for the comparison function it mentions that two checks are made, one between the direction of the normals, which cannot exceed a certain angular threshold, and a second one saying that the 'd' component of the normal cannot exceed a certain distance threshold. I think the first statement is pretty clear, and for the second one I assumed the rationale was, if the planar equation is given by a1*x1 + b1*y1 + c1*z1 + d1 = 0with (a1, b1, c1) being the normal components in point (x1, y1, z1). This meant that

| d1 - d2 | = |(a2*x2 + b2*y2 + c2*z2) - (a1*x1 + b1*y1 + c1*z1)| < thrs

Now the way the current function is implemented, it just compares if the distance between two points is below this threshold, which is wrong.

I'm still unsure about the following points:

  • there's a boolean variable called depth_dependent_ which I still do not fully understand, but it seems to normalize/scale the threshold. Can anyone shed some light on the rationale behind it?
  • Can I assume that all normals have unit norm? Because otherwise this d component residue will be a lot different, depending on the norm of the normal, and I'll need to normalize them beforehand.
  • There are currently only a few files making use of the euclidean cluster comparison e.g., ni_linemod.cpp, pcd_select_object_plane.cpp, organized_segmentation_demo.cpp, stereo_ground_segmentation.cpp, and none of these ever even sets the inputs norms. So what I did was to retain the old behaviour if no normals were specified. Personally this doesn't feel correct, and I think it would be best to print an error message and abort the comparison if possible. Comments on how to proceed are appreciated.
  • Finally, I wanted to write some unit tests for this. I don't see much tests in segmentation folder. Should I start another file just for the euclidean_cluster_comparator (and probably euclidean segmentation) or is there a more adequate filename (agregating more other tests).
  • What's the logical difference between the EuclideanClusterComparator and the EuclideanPlaneCoefficientComparator?

Sorry for the trouble

float dx = input_->points[idx1].x - input_->points[idx2].x;
float dy = input_->points[idx1].y - input_->points[idx2].y;
float dz = input_->points[idx1].z - input_->points[idx2].z;
float dist = sqrtf (dx*dx + dy*dy + dz*dz);
Copy link
Contributor

Choose a reason for hiding this comment

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

float dist = (points[idx1].getVector3fMap() - points[idx2].getVector3fMap()).norm();
Should work and is more elegant / less error prone.

Copy link
Member Author

Choose a reason for hiding this comment

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

👍 although in my opinion this entire block should be scrapped :)

@SergioRAgostinho
Copy link
Member Author

@atrevor Think you can help us here? :)

@taketwo
Copy link
Member

taketwo commented Feb 19, 2016

Hi Sergio, thanks for looking into this. Unfortunately I'm short in time now and next week, but I'll definitely provide comments later.

…parator

Fixes PointCloudLibrary#1514. The functionality intended for the EuclideanClusterComparator appears to be clustering based on Euclidean distance only, hence all normal pertaining information is misleading.
@SergioRAgostinho SergioRAgostinho force-pushed the eucl_clst_cmp branch 2 times, most recently from 97949ae to 8c3e03f Compare July 10, 2017 18:25
@SergioRAgostinho SergioRAgostinho changed the title [WIP] Euclidean cluster comparator now makes use of normals Removed normal related accessors and types from EuclideanClusterComparator Jul 10, 2017
@SergioRAgostinho
Copy link
Member Author

Looking into this more than a year later made me realize that I got things wrong the first time I addressed the underlying issue being reported.

The EuclideanClusterComparator is nothing more than a simple distance based cluster strategy. Everywhere it's actually used, the implementation seemed to suggest exactly that.

For doing normal and distance comparison, the EuclideanPlaneCoefficientComparator is the way to go.

Also, looking into the child classes from pcl::Comparator, the EuclideanClusterComparator is the only one with a name suggestive enough for it to be responsible for performing euclidean distance clustering.

@SergioRAgostinho SergioRAgostinho added this to the pcl-1.9.0 milestone Jul 10, 2017
@SergioRAgostinho SergioRAgostinho added needs: code review Specify why not closed/merged yet and removed status: needs decision labels Jul 10, 2017
@jolesinski
Copy link
Contributor

Hi, I think that not only normals should be cleaned here. What is the point of the label check in the comparator? Whatever it is, I think that it should be optional. Now there is a crash from uninitialized labels pointer if it is not set before clustering.

@SergioRAgostinho
Copy link
Member Author

SergioRAgostinho commented Jul 11, 2017

Based on what I could tell from the files which actually use the class, it's meant to group points from the input point cloud, under a similar index. Basically it provides the id of the segment the point belongs to.

In the comparator, then you can specify if you want to use certain label for comparisons or not. I'll need to revise this again having that in mind.

@SergioRAgostinho SergioRAgostinho added needs: more work Specify why not closed/merged yet needs: code review Specify why not closed/merged yet and removed needs: code review Specify why not closed/merged yet needs: more work Specify why not closed/merged yet labels Jul 11, 2017
Copy link
Contributor

@jolesinski jolesinski left a comment

Choose a reason for hiding this comment

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

Hi, got some minor comments, but +1 from me. Now it will be possible to use organized segmentation just as in euclidean cluster extraction tutorial, thanks.

@@ -50,31 +50,25 @@ namespace pcl
*
* \author Alex Trevor
*/
template<typename PointT, typename PointNT, typename PointLT>
template<typename PointT, typename PointLT>
Copy link
Contributor

Choose a reason for hiding this comment

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

If labels are now optional, can the template label default to PointLT = pcl::Label?

@@ -162,22 +124,21 @@ namespace pcl
exclude_labels_ = boost::make_shared<std::vector<bool> >(exclude_labels);
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks weird, I see no point for copying excludes to a shared pointer and they should be passed as const

Copy link
Member Author

@SergioRAgostinho SergioRAgostinho Jul 13, 2017

Choose a reason for hiding this comment

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

Agreed. I didn't change originally because it's not breaking anything at this point and it would be an additional thing breaking the API.

assert (labels_->size () == input_->size ());
const uint32_t &label1 = labels_->at (idx1).label;
const uint32_t &label2 = labels_->at (idx2).label;
if ( (*exclude_labels_)[label1] || (*exclude_labels_)[label2])
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider exclude_labels_->at(label) to be user proof

Copy link
Member Author

Choose a reason for hiding this comment

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

Is it really necessary? Both labels_ and exclude_labels_ are set by the user... I would personally just let it explode and have the user debug it.

@@ -191,16 +152,13 @@ namespace pcl
float dy = input_->points[idx1].y - input_->points[idx2].y;
float dz = input_->points[idx1].z - input_->points[idx2].z;
float dist = std::sqrt (dx*dx + dy*dy + dz*dz);
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be wrapped with pcl::geometry::distance(input_->at(idx1), input_->at(idx2))

Copy link
Member Author

Choose a reason for hiding this comment

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

I would actually just use eigen for it. I'll change it only if the rewrite is requested.

@@ -8,6 +8,8 @@ set(build TRUE)
PCL_SUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSYS_DESC}" ${DEFAULT} "${REASON}")
PCL_SUBSYS_DEPEND(build "${SUBSYS_NAME}" DEPS ${SUBSYS_DEPS} OPT_DEPS ${OPT_DEPS})

include_directories(${VTK_INCLUDE_DIRS})
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like some other PR

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, for some reason my test was not compiling, but there's no reason to add this in this PR.

@SergioRAgostinho
Copy link
Member Author

Before going through your comments let me just disclaim that my intention was really to change as less things as possible.

If the general opinion is that I should do a proper rewrite of the thing there's gonna be more things to probably alter.

Thank you for taking time and reviewing the thing. Is good to see people involved.

@SergioRAgostinho SergioRAgostinho force-pushed the eucl_clst_cmp branch 2 times, most recently from df8146e to 6b8117e Compare July 14, 2017 12:55
@SergioRAgostinho
Copy link
Member Author

SergioRAgostinho commented Jul 14, 2017

The previous implementation of the exclude_labels_ as a vector "imposed" that all labels used had to be be sequentially numbered and starting at 0. The map lifts such a restriction.

@@ -93,14 +95,15 @@ namespace pcl
* \param depth_dependent
*/
inline void
setDistanceThreshold (float distance_threshold, bool depth_dependent)
setDistanceThreshold (const float &distance_threshold,
Copy link
Member

Choose a reason for hiding this comment

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

Why did these become references?

Copy link
Member Author

Choose a reason for hiding this comment

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

Originally I thought: You have only a single copy, inside the body of the function. But then again, when you pass a reference I think you're passing the underlying pointer type into the function. You still have two copies in the end right: 1 pointer + 1 native type. I'll just revert it to what it was.

{
labels_ = labels;
}

const boost::shared_ptr<const std::map<uint32_t, bool> >&
Copy link
Member

Choose a reason for hiding this comment

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

Maybe a typedef for this will improve readability?

Copy link
Member Author

Choose a reason for hiding this comment

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

👍

{
distance_threshold_ = distance_threshold;
depth_dependent_ = depth_dependent;
}

/** \brief Get the distance threshold in meters (d component of plane equation) between neighboring points, to be considered part of the same plane. */
inline float
inline const float&
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Again: preventing a copy if you don't desire one. But in the end I'm not sure what exactly happens under the hood, when you create a reference.

Copy link
Member

Choose a reason for hiding this comment

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

You would gain nothing as you would need to create a pointer ;).

Copy link
Member Author

Choose a reason for hiding this comment

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

What I feared ^^ I'll revert it.

@taketwo taketwo removed the needs: code review Specify why not closed/merged yet label Jul 17, 2017
}
boost::shared_ptr<std::map<uint32_t, bool> > plane_labels = boost::make_shared<std::map<uint32_t, bool> > ();
for (size_t i = 0; i < label_indices.size (); ++i)
(*plane_labels)[i] = (label_indices[i].indices.size () > min_plane_size)? true : false;
Copy link
Member Author

Choose a reason for hiding this comment

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

Just noticed I did something useless here (and the other repetitions of this pattern). This can be reduced to:

(*plane_labels)[i] = (label_indices[i].indices.size () > min_plane_size);

🤦‍♂️

I'll submit the change at some point.

@SergioRAgostinho
Copy link
Member Author

Should be good for merging, once Travis get's back on track. https://www.traviscistatus.com/incidents/4vdl52d28hz3

@taketwo taketwo merged commit 857a197 into PointCloudLibrary:master Nov 3, 2017
@atrevor
Copy link
Contributor

atrevor commented Nov 3, 2017

Sorry to comment so late on this, but thanks for the cleanup @SergioRAgostinho and @taketwo ! IIRC I had intended to optionally use normals in addition to distance for the clustering, but seems like I didn't get around to it at the time this got merged. Probably best to keep it simple anyway. Thanks again!

@SergioRAgostinho
Copy link
Member Author

Hey

I had intended to optionally use normals in addition to distance for the clustering

How exactly? (I'm assuming it is something different than what is done in EuclideanPlaneCoefficientComparator)

@SergioRAgostinho SergioRAgostinho deleted the eucl_clst_cmp branch November 6, 2017 21:10
@taketwo taketwo added changelog: ABI break Meta-information for changelog generation changelog: API break Meta-information for changelog generation labels Nov 16, 2017
@taketwo
Copy link
Member

taketwo commented Nov 16, 2017

(Updating to PCL master broke our library at work without any "depreciation warning" ceremony 😆)

BTW, why did you decide to go for a map with excluded labels? Isn't a set more semantically clear?

@SergioRAgostinho
Copy link
Member Author

Oh true... crap. Maybe I should re add the methods and set them to deprecated before the next release.

BTW, why did you decide to go for a map with excluded labels? Isn't a set more semantically clear?

True. I overlooked that detail. You just need to know if the label is the set or not. The true vs false value redundant.

@taketwo
Copy link
Member

taketwo commented Nov 16, 2017

I guess my "code review" was a fail 😢

@SergioRAgostinho SergioRAgostinho added changelog: removal Meta-information for changelog generation and removed changelog: ABI break Meta-information for changelog generation labels Sep 2, 2018
@SergioRAgostinho
Copy link
Member Author

I'm removing both the removal and the breaks ABI labels because we actually provided proper deprecation in #2096.

@SergioRAgostinho SergioRAgostinho removed changelog: API break Meta-information for changelog generation changelog: removal Meta-information for changelog generation labels Sep 25, 2018
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.

6 participants