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

add 'boundingBox' to NmlParser and NmlWriter #2827

Merged
merged 10 commits into from
Jul 5, 2018
Merged

Conversation

rschwanhold
Copy link
Contributor

@rschwanhold rschwanhold commented Jun 28, 2018

Mailable description of changes:

  • We now write the bounding box of a SkeletonTracing into the nml.
    Example: <taskBoundingBox topLeftX="0" topLeftY="0" topLeftZ="0" width="512" height="512" depth="512" />
  • We also parse the bounding box when uploading an nml file.
    • There are four possible scenarios when uploading a nml file because it is still possible to specify the bounding box explicitly in the form-value BoundinBox:
    1. the bounding box is specified in the form-value but NOT in the parsed nml
      => the bounding box of the form-value is used
    2. the bounding box is specified in the form-value AND in the parsed nml
      => the bounding box of the form-value is used
    3. the bounding box is NOT specified in the form-value but in the parsed nml
      => the bounding box of the parsed NML is used
    4. the bounding box is NEITHER specified in the form-value nor in the parsed nml
      => no bounding box is used

Steps to test:

  • Export the Nml of a Task via /api/annotations/:typ/:id/download
    • make sure the nml has a field boundingBox if the task has a boundingBox (this is optional)
  • Import the Task again (Administration >> Tasks >> add Task >> 'Upload nml file')
    • try setting the boundingBox in the form explicit (the form value has a higher priority)
    • make sure the new Task has the specified boundingBox (from the form or the nml)

Issues:


  • Ready for review

@fm3 fm3 requested review from jstriebel and youri-k June 28, 2018 14:21
Copy link
Contributor

@jstriebel jstriebel left a comment

Choose a reason for hiding this comment

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

Please add some comments, that explain which bounding box takes precendence when & (especially) why. On which layers do we have bounding boxes now?

@@ -99,13 +99,15 @@ class TaskController @Inject() (val messagesApi: MessagesApi)
}

private def buildFullParams(nmlParams: NmlTaskParameters, tracing: SkeletonTracing, fileName: String, description: Option[String]) = {
val parsedTracingBoundingBox = tracing.boundingBox.map(b => BoundingBox(b.topLeft, b.width, b.height, b.depth))
val bbox = if(nmlParams.boundingBox.isDefined) nmlParams.boundingBox else parsedTracingBoundingBox
Copy link
Contributor

Choose a reason for hiding this comment

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

why does it make sense to give the nml bounding box precedence?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nmlParmsare the form-parameter that you specify when you are uploading an nml. There you can specify a bounding box explicitly (this is optional).
The bounding box parsedTracingBoundingBox is the bounding box which might be stored inside the nml (this is optional as well).

When you are uploading an nml and you are specifying the bounding box in the form-value explicitly then you are aware which bounding box you want. (Therefore this value is used)
When you don't specify a bounding box in the form-value then the bounding box of the parsed nml is used. (In case none of those two are specified, then the bounding box is None)

Copy link
Contributor

Choose a reason for hiding this comment

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

@rschwanhold: Thanks for the explanation! I thought the variables are exactly the opposite^^
Therefore I renamed them here to make this more clear.

@@ -56,14 +56,15 @@ object NmlParser extends LazyLogging with ProtoGeometryImplicits {
val editPosition = parseEditPosition(parameters \ "editPosition").getOrElse(SkeletonTracingDefaults.editPosition)
val editRotation = parseEditRotation(parameters \ "editRotation").getOrElse(SkeletonTracingDefaults.editRotation)
val zoomLevel = parseZoomLevel(parameters \ "zoomLevel").getOrElse(SkeletonTracingDefaults.zoomLevel)
val userBoundingBox = parseUserBoundingBox(parameters \ "userBoundingBox")
val userBoundingBox = parseBoundingBox(parameters \ "userBoundingBox")
val boundingBox = parseBoundingBox(parameters \ "boundingBox")
Copy link
Contributor

Choose a reason for hiding this comment

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

is this simply None if boundingBox does not exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

boundingBox is None if the parsed nml does not contain information about this bounding box


logger.debug(s"Parsed NML file. Trees: ${trees.size}, Volumes: ${volumes.size}")

if (volumes.size >= 1) {
(Right(VolumeTracing(None, BoundingBox.empty, time, dataSetName, editPosition, editRotation, ElementClass.uint32, None, 0, 0, zoomLevel), volumes.head.location), description)
} else {
(Left(SkeletonTracing(dataSetName, trees, time, None, activeNodeId,
(Left(SkeletonTracing(dataSetName, trees, time, boundingBox, activeNodeId,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why should the boundingBox be part of the NML? I thought this belongs rather to the dataset than to a tracing?

Copy link
Contributor Author

@rschwanhold rschwanhold Jun 29, 2018

Choose a reason for hiding this comment

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

In

optional BoundingBox boundingBox = 4;
you can see that the bounding box is already part of a skeletonTracing.
The reason why we want to write the bounding box to the nml is that after you've downloaded the nml of a SkeletonTracing and then you are uploading it again, you dont't want to lose the bounding box. (see: https://discuss.webknossos.org/t/bounding-box-should-be-persisted-to-parsed-from-nml/966)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, thanks! 👍 I wasn't aware of that layer.

@daniel-wer
Copy link
Member

daniel-wer commented Jun 29, 2018

@rschwanhold Two things:
(1) This should probably be implemented in the frontend NML writer as well, right?
(2) I'm not sure whether we're mixing up bounding boxes here, I just want to be sure we're on the same page. From my understanding there can be a taskBoundingBox (which is what this PR is about). This taskBoundingBox (I would use this name to make it clear) will be persisted to the NML if it is there.
There also is an optional userBoundingBox (which the user may define and which is persisted in the NML as the userBoundingBox).
If both are present, both should be persisted in the NML.

Is this your understanding as well? :)

@rschwanhold
Copy link
Contributor Author

rschwanhold commented Jun 29, 2018

@daniel-wer
(1) I forgot about this. Do you want to do this or should I try it?
(2) That is correct: we have two bounding boxes (one for the task and one for the user).
The the userBoundingBox was already persisted in the NML as you can see in

val userBoundingBox = parseUserBoundingBox(parameters \ "userBoundingBox")
.

I think renaming boundingBox to taskBoundingBox is a good idea.
Should I also rename the variable from the SkeletonTracing to taskBoundingBox or should I only rename this in the context of the NML?

@youri-k
Copy link
Contributor

youri-k commented Jun 29, 2018

I don't know how renaming this would affect the already stored proto data and if they need a migration

rschwanhold and others added 2 commits June 29, 2018 11:14
nmlParams --> nmlFormParams
parsedTracingBoundingBox --> parsedNmlTracingBoundingBox
@daniel-wer
Copy link
Member

(1) I'll take care of that as part of this PR :)
(2) Let's only rename it in the NML for now, as @youri-k already mentioned, I'm also not aware of the implications of changing the name in the SkeletonTracing

@jstriebel jstriebel dismissed their stale review June 29, 2018 09:22

the backend code LGTM

@daniel-wer
Copy link
Member

I've implemented the frontend part, updated the nml snapshots and added some more tests for invalid nmls. @philippotto Please have a look at the frontend changes in c7f598a.

Copy link
Member

@philippotto philippotto left a comment

Choose a reason for hiding this comment

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

Nice 🎉 Cool that you added more front-end tests, @daniel-wer 👍

topLeftX: bb.min[0],
topLeftY: bb.min[1],
topLeftZ: bb.min[2],
width: bb.max[0] - bb.min[0],
Copy link
Member

Choose a reason for hiding this comment

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

Can you use convertFrontendBoundingBoxToServer from reducer_helpers.js here like this?

const [topLeft, width, height, depth] = convertFrontendBoundingBoxToServer(bb);
const [topLeftX, topLeftY, topLeftZ] = topLeft;
return serializeTag(name, { topLeftX, topLeftY, topLeftZ, width, height, depth });

Then, we don't duplicate the max - min logic :)

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I see, you moved the code. But maybe it's a good idea, anyway, to reduce the boundingbox-related code a bit.

Copy link
Contributor

@youri-k youri-k left a comment

Choose a reason for hiding this comment

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

backend part LGTM

@rschwanhold rschwanhold merged commit 219bcaa into master Jul 5, 2018
@daniel-wer daniel-wer deleted the make-bbox-persisted branch July 12, 2018 11:31
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.

Bounding box should be persisted to / parsed from nml
5 participants