Contour ID Continuity bug / new feature?

Howdy! I’m using the contour FF plugin to recognize IR reflectors on dancers. I am having a problem in that the plugin “re-uses” IDs across frames when it really shouldn’t. Specifically in cases where from one frame to the next an old marker disappears and a new one appears; the new marker, no matter how far away, will get assigned on old marker number. This wrecks havoc with marker speed/velocity computations. The “Unique ID” setting does not change this behavior in either state.

By looking at the code, it appears to always reassign IDs to the nearest old marker. So it looks to me that if there was a “max nearness” input parameter, that if exceeded, would result in a new ID number being assigned and fix my problem.

I’m happy to make this change, but I wanted to run this by folks first to see if my understanding is correct, and see if y’all had any pointers as to where in the code this change should be made. Also, tips/pointers on compiling this to run with vvvv would be helpful. I use VS, and would prefer to do it that route - is codeblocks required for compiling?

Thanks a bunch!

hei dog,

actually the Unique ID is supposed to do exactly that. only always hand out new IDs, never reuse old IDs. and checking the helppatch it actually does so. can you confirm this? is your application different than the helppatch?

anyway i’ve never tried compiling this with visualstudio but don’t see a reason why it shouldn’t do.

The problem is if a contour disappears and another appears in the same frame. Contour will assign the old contour ID, no matter how far away the new contour is.

See the attached.

Thanks joreg!

Contour help - ID bug.v4p (26.1 kB)

ah ok,

sounds like a plausible special case not tested back then when the contour was written. so if you find a solution for this (codewise) please don’t hesitate to send it over.

also if you have any specific troubles getting it to work/compile…just ask…it’s been a while though since that code was last touched.

joreg, I was hoping you might have a pointer just where in the code this should occur ;^). I’ve looked through it, and have some ideas, but if you remember it… There is also a section marked “TODO” (Arry1 > Array2) - whasup wid’ dat?

This “special case” is actually extremely common in my use of it, where I have three dancers each with seven IR reflective markers on. As they move, the markers are constantly popping in and out of view and this problem happens almost every second or so in the active parts.

Thanks a bunch!

mkay, i had a look at the code (which i didn’t write btw) and have to say i think it would be best to rewrite the adaptIndex() function as it looks overly complicated to me. looks like this could be done which muss less code and still all code outside of this function could be left alone.

for my understanding what this function is supposed to do, is mapping the list of new objects to the list of old objects. it does this by comparing the distances of the objects centers.

so in pseudocode i’d suggest something like:

for i=0 to newObject.Count-1
  matchingOldObj = newObject[i](i).FindMatchingOldObject();
  if matchingOldObj = null
    if UniqueIDs 
      IDs_new[i](i) = FMaxID++;
      IDs_new[i](i) = FLowestFreeID;
    IDs_new[i](i) = matchingOldObj.ID

and as you suggested, in FindMatchingOldObject() you’d have the MaxDistance parameter to decide if an object is an option at all for a match. this probably would do for your case while obviously this function could be much more intelligent by comparing for more parameters than the just the distance between objects, but that would require more modification to the code…

also we’d still have to figure out how the Sortlist parameter is supposed to be layed out since following code obviously depends on it.

and the FMaxID in the pseudocode above would be the inc in the current implementation.

does that make sense to you?

Ayup, I have gone through the adaptindex() code too. I think the basic approach it uses is relatively sound (scoring ALL possible pairs before doing assignments) but I also found the code hard to untangle. In general I prefer not to drastically alter public code, as others may understand its current structure and I wouldn’t want to pull the rug out from under them, but that function does seem like a good candidate for a re-write.

I’ll make a pass at it. Thanks again!

just to let you know the guy who wrote this years ago is no longer working on anything vvvv releated. it will be very much appreciated if you can improve that code.

Finally getting time to so some housecleaning. I have a working version of this change that builds cleanly in VS2010. But there were some project changes that needed to be made to compile it with the current openCV.

I wanted to add some “smarts” to it so it would store a vector for each contour ID and use the expected position to determine nearness, but was too busy. So it just takes a “max delta” parameter to determine if it should reuse a contour ID. Can still be fooled, but much less often than before.

How should I get these changes integrated? I don’t want to break the existing version’s build. Should I call it ContourV2 or something? Keep it completely separate and put the whole package in contributions?


hi mediadog!

please compare your solution with the workarounds presented here:

  • one workaround spits out new (smaller) ids that you can work with (e.g. using them directly as a slice index for filtering)
  • another workaround takes care of ids that suddenly appear somewhere else by measuring the distance to the last frame; this one might be superfluous after your modifications described above.

would be nice if we also could get rid of the first workaround by generating ids like that “reindex” patch does.

what do you think? thanks!

Hey sebastien! Thanks for the thoughtful reply. I liked the presentation, good to know my desire for/pain dealing with missing features is not unique.

The problem I am having with Contour, and the problem with dynamic spreads, are actually two different things. In the case of dealing with particle systems we generate, we have apriori information about the identity of the particles, and the issue is keeping them properly managed in dynamic spreads.

In my case, the particle system already exists out in the world (the IR markers on the dancers), and the primary issue is Contour assigning the particles a consistent identity. That has to be done before the dynamic spread problem can be addressed with success.

Assigning those identities is non-trivial, and can actually never be done with 100% confidence. But by looking at a particle’s history/behavior, better guesses can be made. And yes, that means maintaining state in Contour, a whole can of worms I am only now (thanks to your reply and presentation) starting to appreciate fully.

And you have helped me clarify a problem I am having with my monobuf/monodata when expanding them to work with spreads. Thanks again!

hey mediadog,

concerning “How should I get these changes integrated?” please follow vvvv sdk and send us a pull-request.

any progress on this?

just finished a small plugin, in case someone needs something like this.

it is probably not the fastest of all solutions for this problem, but it works quite well for a low count of blobs.

note: once the devvvvs take care of a few small changes on basic vvvv datatypes, this could go into the generic project.

edit: uploaded file removed, it is now in this contribution

Track (Vector3D) helps with a lot of those issues, what’s still missing is a good way to use the Animation nodes within. Maybe someone else has an idea.