1

I have stored the defects using convexity defects in an 4 element vector integer array using vec4i.

My convex hull array is in hull element and contours in Contours; What i want to do is draw a line from start point of a convexity defect to the end point of one. For this i need to access the element start index which is present in the vec4i of a defects vector!

How do i do this??

   #include <opencv\cv.h>
#include <opencv2\highgui\highgui.hpp>
#include<opencv\cvaux.h>
#include<opencv\cxcore.h>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
#include<conio.h>
#include <stdlib.h>



using namespace cv;
using namespace std;

int main(){


    Mat img, frame, img2, img3;


    VideoCapture cam(0);
    while (true){
        cam.read(frame);
        cvtColor(frame, img, CV_BGR2HSV);
        //thresholding 
        inRange(img, Scalar(0, 143, 86), Scalar(39, 255, 241), img2);

        imshow("hi", img2);

        //finding contours
        vector<vector<Point>> Contours;
        vector<Vec4i> hier;
        //morphological transformations
        erode(img2, img2, getStructuringElement(MORPH_RECT, Size(3, 3)));
        erode(img2, img2, getStructuringElement(MORPH_RECT, Size(3, 3)));

        dilate(img2, img2, getStructuringElement(MORPH_RECT, Size(8, 8)));
        dilate(img2, img2, getStructuringElement(MORPH_RECT, Size(8, 8)));


        //finding the contours required
        findContours(img2, Contours, hier, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, Point(0, 0));



        //finding the contour of largest area and storing its index
        int lrgctridx = 0;
        int maxarea = 0;
        for (int i = 0; i < Contours.size(); i++)
        {
            double a = contourArea(Contours[i]);
            if (a> maxarea)
            {
                maxarea = a;
                lrgctridx = i;
            }

        }
        //convex hulls
        vector<vector<Point> >hull(Contours.size());
        vector<vector<Vec4i>> defects(Contours.size());
        for (int i = 0; i < Contours.size(); i++)
        {
            convexHull(Contours[i], hull[i], false);
            convexityDefects(Contours[i], hull[i], defects[i]);
        }
        //REQUIRED contour is detected,then convex hell is found and also convexity defects are found and stored in defects




        if (maxarea>100){
            drawContours(frame, hull, lrgctridx, Scalar(255, 255, 255), 1, 8, vector<Vec4i>(), 0, Point());
        \\ drawing the required lines joining defects!im facing problem on how to acheive this since i dont know how to access the elements stored in defects
           line(frame, \\startindex, \\endindex, \\color, 1);

        }


        imshow("output", frame);
        char key = waitKey(33);
        if (key == 27) break;



    }

}

Also my output window shows error when i add the convexityDefects(..) line i think it is in wrong format! Thanks in advance.

Sridhar Thiagarajan
  • 580
  • 1
  • 7
  • 20
  • what's stored in the Vec4i ? – Miki Jul 11 '15 at 13:24
  • I have added my code. I have tried and stored the information about the convexity defects in the the 4 element vector array.Also my output window crashes on adding the line convexityDefects(...) in the code.I think it is formatted wrongly. – Sridhar Thiagarajan Jul 11 '15 at 13:58
  • that code seems familiar.. :D – Miki Jul 11 '15 at 14:03
  • That is because i posted part of it yesterday..im learning step by step..working on hand gesture identification! – Sridhar Thiagarajan Jul 11 '15 at 14:09
  • 1
    see my answer. Next time spend a little more time on google and SO – Miki Jul 11 '15 at 14:52
  • I did go through answers..but couldnt understand them properly..as im not too familiar with templates..as i only knew c earlier. Can you please explain the for(const vec4i&v :defects[i]) line Also..if im not mistaken..vector> stores all the points which are part of the convex hull..vector> int stores..the indices..like 0..1..2..and so on(how many ever points are present) and vec4i stores the 4 things about the defects(start index,end and so on) – Sridhar Thiagarajan Jul 11 '15 at 15:30
  • it a [range based for](http://en.cppreference.com/w/cpp/language/range-for), it is basically the standard for loop, but you don't need the indices. – Miki Jul 11 '15 at 15:45
  • it stores the indices to the points, instead of the points themselves. – Miki Jul 11 '15 at 15:46
  • read abouot it [here](http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#convexitydefects) – Miki Jul 11 '15 at 15:47
  • however, does the code works ok? – Miki Jul 11 '15 at 15:48
  • Yea..the code works..i need to work with the depth parameter..it is showing erraneous results!I have however understood the concept..the range for loop is still not very clear..after reading.. for(vec4i&v :defects[i]) this means we are going through defects[i] but what does vec4i& v mean exactly. – Sridhar Thiagarajan Jul 11 '15 at 16:34
  • I thought the code was working...my bad..that was the previous one without any edits...i get a list of errors i,v are undeclared identifiers..what type must i declare them as..i tried both as integers but gives an error – Sridhar Thiagarajan Jul 11 '15 at 17:05
  • which i,v are undeclared? – Miki Jul 11 '15 at 17:07
  • The ones used in the code snippet posted – Sridhar Thiagarajan Jul 11 '15 at 17:29
  • there are no undeclared variables in the code. I posted the full solution removing the range base for and using a regular for statement. – Miki Jul 11 '15 at 17:37
  • ok, now also draw only the errors for the selected contour – Miki Jul 11 '15 at 17:46
  • hoping that's enough to answer to your question: _What i want to do is draw a line from start point of a convexity defect to the end point of one._ – Miki Jul 11 '15 at 17:54
  • Could you explain vec4i&v =defects[][] line please? – Sridhar Thiagarajan Jul 11 '15 at 18:07
  • it's a const reference to a Vec4i, which is the object contained in detects[i][j], since is `vector> defects;` Read about it on any C++ book. – Miki Jul 11 '15 at 18:12
  • Thanks for the help..much appreciated :) – Sridhar Thiagarajan Jul 12 '15 at 05:18

1 Answers1

6

convexityDefects needs a

Convex hull obtained using convexHull() that should contain indices of the contour points that make the hull.

that contains more than 3 indices. So you need this:

vector<vector<Point> >hull(Contours.size());
vector<vector<int> > hullsI(Contours.size()); // Indices to contour points
vector<vector<Vec4i>> defects(Contours.size());
for (int i = 0; i < Contours.size(); i++)
{
    convexHull(Contours[i], hull[i], false);
    convexHull(Contours[i], hullsI[i], false); 
    if(hullsI[i].size() > 3 ) // You need more than 3 indices          
    {
        convexityDefects(Contours[i], hullsI[i], defects[i]);
    }
}

Then your drawing part is (adapted from here):

/// Draw convexityDefects
for (int i = 0; i < Contours.size(); ++i)
{
    for(const Vec4i& v : defects[i])
    {
        float depth = v[3] / 256;
        if (depth > 10) //  filter defects by depth, e.g more than 10
        {
            int startidx = v[0]; Point ptStart(Contours[i][startidx]);
            int endidx = v[1]; Point ptEnd(Contours[i][endidx]);
            int faridx = v[2]; Point ptFar(Contours[i][faridx]);

            line(frame, ptStart, ptEnd, Scalar(0, 255, 0), 1);
            line(frame, ptStart, ptFar, Scalar(0, 255, 0), 1);
            line(frame, ptEnd, ptFar, Scalar(0, 255, 0), 1);
            circle(frame, ptFar, 4, Scalar(0, 255, 0), 2);
        }
    }
}   

Complete code

#include <opencv2\opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
    Mat img, frame, img2, img3;
    VideoCapture cam(0);
    while (true){
        cam.read(frame);

        cvtColor(frame, img, CV_BGR2HSV);

        //thresholding 
        inRange(img, Scalar(0, 143, 86), Scalar(39, 255, 241), img2);

        imshow("hi", img2);

        //finding contours
        vector<vector<Point>> Contours;
        vector<Vec4i> hier;
        //morphological transformations
        erode(img2, img2, getStructuringElement(MORPH_RECT, Size(3, 3)));
        erode(img2, img2, getStructuringElement(MORPH_RECT, Size(3, 3)));

        dilate(img2, img2, getStructuringElement(MORPH_RECT, Size(8, 8)));
        dilate(img2, img2, getStructuringElement(MORPH_RECT, Size(8, 8)));

        //finding the contours required
        findContours(img2, Contours, hier, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, Point(0, 0));

        //finding the contour of largest area and storing its index
        int lrgctridx = 0;
        int maxarea = 0;
        for (int i = 0; i < Contours.size(); i++)
        {
            double a = contourArea(Contours[i]);
            if (a> maxarea)
            {
                maxarea = a;
                lrgctridx = i;
            }
        }
        //convex hulls
        vector<vector<Point> >hull(Contours.size());
        vector<vector<int> > hullsI(Contours.size()); 
        vector<vector<Vec4i>> defects(Contours.size());
        for (int i = 0; i < Contours.size(); i++)
        {
            convexHull(Contours[i], hull[i], false);
            convexHull(Contours[i], hullsI[i], false); 
            if(hullsI[i].size() > 3 )            
            {
                convexityDefects(Contours[i], hullsI[i], defects[i]);
            }
        }
        //REQUIRED contour is detected,then convex hell is found and also convexity defects are found and stored in defects

        if (maxarea>100){
            drawContours(frame, hull, lrgctridx, Scalar(2555, 0, 255), 3, 8, vector<Vec4i>(), 0, Point());

            /// Draw convexityDefects
            for(int j=0; j<defects[lrgctridx].size(); ++j)
            {
                const Vec4i& v = defects[lrgctridx][j];
                float depth = v[3] / 256;
                if (depth > 10) //  filter defects by depth
                {
                    int startidx = v[0]; Point ptStart(Contours[lrgctridx][startidx]);
                    int endidx = v[1]; Point ptEnd(Contours[lrgctridx][endidx]);
                    int faridx = v[2]; Point ptFar(Contours[lrgctridx][faridx]);

                    line(frame, ptStart, ptEnd, Scalar(0, 255, 0), 1);
                    line(frame, ptStart, ptFar, Scalar(0, 255, 0), 1);
                    line(frame, ptEnd, ptFar, Scalar(0, 255, 0), 1);
                    circle(frame, ptFar, 4, Scalar(0, 255, 0), 2);
                }
            }
        }

        imshow("output", frame);
        char key = waitKey(33);
        if (key == 27) break;

    }
}
Community
  • 1
  • 1
Miki
  • 40,887
  • 13
  • 123
  • 202
  • Thanks for your example. It mostly works fine with the only exception that convexHull(Contours[i], hullsI[i], false); needs "true" clockwise parameter. Perhaps this is opencv 3+ thing. Using false leads to inability to find all defects. – Cynichniy Bandera Oct 03 '17 at 10:03
  • @Umka the `false` is to return indices (instead of points) which are needed by the `convexityDefects` function. Not really sure what you're talking about, actually – Miki Oct 03 '17 at 11:30
  • In my opencv 3.3 there is such a convexityHull(): CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true ); This is what I mean. – Cynichniy Bandera Oct 03 '17 at 12:05
  • 1
    @Umka yes, you're right. That `false` is for `clockwise`, but I intented to use it for `returnPoints`. Luckily I passed a `vector`, so the `returnPoints` flag was ignored anyway. Then it problably changes if you do CW or CCW... I don't know actually. Thanks for the feedback ;) – Miki Oct 03 '17 at 12:12
  • You have no idea how long it took me to find an example of drawing contour defects. Thank you sir :-) – Darth Coder Aug 22 '18 at 20:15