kylemcdonald / ofxCv

Alternative approach to interfacing with OpenCv from openFrameworks.
Other
655 stars 276 forks source link

Method to get convex hull and convex hull defects as indices ? #83

Open philworthy opened 11 years ago

philworthy commented 11 years ago

Hi Kyle.

I'm fairly new to c++ so please excuse me if any of this is obvious, and apologies to post as an issue - just wasn't sure how else to ask)

I'm trying to describe a contour of a blob in terms of concave and convex sections but running into some trouble. I need to extract the indices of convex hulls and their defects (I need to do further processing on all the contour points, which is why I need just indices), but the methods in ofxCv return polylines, or vectors of points, which will be awkward to turn back into indices without hacks like finding nearest points. I dug a little deeper and it looks like OpenCv is able to return this data as indices, but unless I'm mistaken only if using the c++ OpenCv API (I saw a code comment that implied you were using the C API, but to be honest this is where I get out of my depth). I spent a few days trying to tweak ofxCv and ofxOpencCv to get what I want but I've hit a wall so I thought I'd reach out incase you or anyone out there knows how to help.

Any advice very very much appreciated.

Thanks -Phil

kylemcdonald commented 11 years ago

as far as i can tell opencv won't return the indices directly, but it will return pointers to the contour points with respect to the hull. so something like the following would get you started with that:

vector<cv::Vec4i> convexityDefects(const vector<cv::Point>& contour, vector<int>* defectIndices = NULL) {
    // at the deepest point in the loop
    if(defectIndices != NULL) {
        defectIndices.push_back(ofFind(hullIndices, cur->start));
        defectIndices.push_back(ofFind(hullIndices, cur->end));
    }
}

that said, unless you need something hyper-optimized because you have thousands of defects, i would just take the defect points and use ofPolyline::getClosestPoint().

philworthy commented 11 years ago

Thanks Kyle. Even if I used 'getClosestPoint' it would still be tricky to get the index out of it though. So it looks like OpenCV 2.4.3 will return indices when the c++ interface is used. I found the compiled libs for XCode here (https://github.com/kamend/ofxOpenCV243) but it's not clear how I tell OpenFrameworks to use the 2.4.3 version. Do you have any experience with that? (Thanks for your help!)

philworthy commented 11 years ago

Incase anyone out there is searching for a similar problem, I found this compiled 2.4.3 opencv worked fine (the one on ofxaddons I linked in previous did not for me for unknown reason). https://twitter.com/wimvanhenden/status/311749897617547264. (I'm on mountain lion with Xcode 4.6.2). Still figuring out the rest, but at least OpenCV is working. :)

philworthy commented 11 years ago

Ok got this working. Posting here for others incase they're looking for something similar. If you need to get convex hull and convex hull defects by index rather than point:

  1. Get OpenCV 2.4.3 from the link in previous message
  2. Make sure all the .a files are linked in your project settings (and unlink the old OpenCV version)
  3. Add a couple of methods to ContourFinder to call the OpenCV methods to return the indices. This might not be 'perfect' code but for example:
vector<int> ContourFinder::getConvexHullIndices(unsigned int i) const {
    vector<int> indices;
    convexHull(Mat(contours[i]), indices, false, false);
    return indices;
}
vector<cv::Vec4i> ContourFinder::getConvexityDefectIndices(unsigned int i) const {
    return convexityDefectIndices(Mat(contours[i]));
}

And off you go. Note convexity defects are returned as cv::Vec4i where [0] = start index [1] = end index [2] = defect index (point 'deepest' in the concave section) [3] = depth (note you have to divide by 256 to get 'real' pixel value

Ok that's it. Hope someone finds it useful. (and thanks Kyle)

bakercp commented 7 years ago

Not entirely related, but I just implemented the

    // this should be replaced by c++ 2.0 api style code once available
    vector<cv::Vec4i> convexityDefects(const vector<cv::Point>& contour) {

using the updated C++ api style and in testing it discovered that the results were different from the existing implementation. Turns out it's a bug.

https://github.com/opencv/opencv/issues/4954

bakercp commented 7 years ago

Here is my "drop in" version of the C++ api using the current oF version of openCV (which has a bug)

It basically makes a best effort to search for the indices in the original contour, but does so as efficiently as possible by first finding the start / end defect indices (which are known to be in the convex hull) and then only searching the full contour between the start / end indices, thus significantly limiting the search of simply polygons.

https://gist.github.com/bakercp/b443755a55b2cc1cbedaaeb75a93ddb6