I’m looking to do the convex hull operation as called-for in the vision white paper for 2012. In WPILib I find the Threshold and the ParticleAnalysis functionality but not convex hull. Where is it?
BTW - I even pulled the svn sources to wpilib and didn’t find reference to it aside from the definition of the C function for the actual IMAQ function externally. Sigh.
I suspect the white paper assumes one is using LabView because doing what is described is anything but trivial in C++ and Java. When searching for documentation on the IMAQ functions I usually get hits on LabView programming topics. Doing the same thing in C++ or Java requires, as far as I can tell, that one use the IMAQ functions in nivision.h and they don’t appear to be well documented. In another post, I outline my approach thus far in C++ and indicate the point at which I am currently stuck.
So, I was hoping to find it as part of BinaryImage:: or MonoImage:: … the reason is: If we’re going to take a ColorImage or HSLImage object and run HSLThreshold() on it, we’ll get a BinaryImage as a result. This is fine.
However, after this step, to do the convexHull operation in “raw imaq API style”, we would have to do a GetImage() from the BinaryImage and toss that into the imaqConvexHull operation…that’s ok, but then we would need to get this back into a BinaryImage in order to run the BinaryImage::GetOrderedParticleAnalysisReports() function and I don’t see a way to get ‘back’ from imaq-land into WPILib C++ land… is there something I’m missing to do that?
I think the problem I encountered was due to some intrinsic differences between functions. Some functions operate on grayscale images (erode) others operate on binary images (convex hull).
I’ve been looking into this too. I noticed that the ParticleAnalysis structure has variables that describe the center of mass. Is it possible that making a particle analysis report performs the convex hull operation?
If not, I’ve thought of a simple algorithm for doing it. Since you know the dimensions of the acquired image you also know how many pixels in each direction. After constructing your binary image from a threshold you can just iterate over every pixel in a single row and fill in the areas between the 2 “activated” pixels (since there are only 2 values in a binary image for every pixel).
What I ended up doing is creating a script using the NI Vision Assistant and then generating code going to “Tools” -> “Generate C Code”. Unfortunately, this code is pretty heavy and has a lot of extra stuff in it for being able to generate generic code. I looked at the different functions they used and then reimplemented them in my own code. The big one is ParticleAnalysis which just has so much overkill in it. I then created my own struct and populated the elements I wanted.
One hint is to use the NIVisionCVI.chm document to find out what each imaqXXXXX function does. The particle analysis is just done with imaqMeasureParticle() for example. The hardest part is learning what functions to use in what order, and by “exporting” your script to C code you can see what NI does. You can then also use the Vision assistant to pick values for thresholding, particle filtering, or whatever you may want to do and see the results instantaneously.
I was a laborious process to be frank, but it should pay off. C is much less demanding than C++, so the function I created should be just about as streamlined as it can get while still using the nivision library.
The convexHull function (imaqConvexHull) does quite a bit actually. Not only does it fill in the holes within a particle but it also REPAIRS EDGES, which I think is quite AMAZING. Manually creating this function could be difficult.
I thought about making src and dest the SAME pointer, but it’s not clear to me that this is ok. Is convexHull() ok with the source and dest being the same?
Not entirely sure, but I think so. In generated vision code from Vision Assistant such as the following they use the same image as a source and destination.
I can tell you for sure that for imaqConvexHull you can use the same source and destination image. I think you can as well for imaqColorThreshold, however the generated code creates another image and copies it, so it’s not as defintive. Basicmanx is using imaqThreshold which is a little different.
As for adding it to binary image, I think they’re making it a little TOO easy this year :). I’ve spent hours pouring over this code…