convexHull in WPILib ??

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.

Thanks,
bob

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.

http://mmrambotics.ca/wpilib/nivision_8h.html#a9788df902e34e1f92306c0c938f03b17

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?

Thanks,
bob

I have found a document that explains a lot about the functions in the IMAQ library:

NI Vision Concepts Manual

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. :slight_smile: Manually creating this function could be difficult.

  • Bryce

P.S. There a other ways as well, I’m sure.

A BinaryImage just contains a member Image pointer. So you can use binaryImage->GetImaqImage() as your source and destination argument.

So, if you already had an image in a BinaryImage object (after Thresholding or something) I guess you might do something like this then?

Image *imaqImage;

imaqImage = binaryImage->GetImaqImage();
imaqConvexHull(imaqImage, imaqImage, TRUE);

Your binaryImage object would then contain a convex hulled image, right?

  • Bryce

I believe so yes. BinaryImage inherits from MonoImage and therefore from ImageBase. If we look at the ImageBase header and source…


//...
public:
    //...
    Image *GetImaqImage();
protected:
    Image *m_imaqImage;


Image *ImageBase::GetImaqImage()
{
    return m_imaqImage;
}

And then a function from BinaryImage, it’s simply using that image.


int BinaryImage::GetNumberParticles()
{
    int numParticles = 0;
    int success = imaqCountParticles(m_imaqImage, 1, &numParticles);
    wpi_setImaqErrorWithContext(success, "Error counting particles");
    return numParticles;
}

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?

bob

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.


VisionErrChk(imaqThreshold(image, image, 215, 255, TRUE, 1));

Well there ya go. I think that’s pretty definitive. If they generate code that uses source and dest as the same, then it’s good in my book. Ha!

Sure would be nice to have an addition to BinaryImage:: which calls out to imaqConvexHull… hint hint…

Thanks,
bob

ConvexHull has been added as a method to Binary Image, at least in WPILibJ. It will probably make its way out in a C++ update sometime soon.

http://firstforge.wpi.edu/sf/go/doc1304?nav=1 (There is some sample code in there)

Bob,

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…

  • Bryce

Thanks. Planning on giving it a try with the team later this week or on Saturday.

bob

I didn’t read all of the previous comments. But the convex hull operation is in nivision.h in WPILib.