如何在Opencv 2.4中使用凸面效果

如何在Opencv 2.4中使用凸面效果,opencv,Opencv,我尝试使用convexHull和convexityDefects来定义手。但是,当程序遇到凸面缺陷时,总会出现一个错误,即“向量下标超出范围”。 这是我的密码 我是否以错误的方式使用了该函数 #include "stdafx.h" #include <opencv2\opencv.hpp> #include <math.h> #include <iostream> using namespace cv; using namespace std; const

我尝试使用
convexHull
convexityDefects
来定义手。但是,当程序遇到凸面缺陷时,总会出现一个错误,即“向量下标超出范围”。 这是我的密码

我是否以错误的方式使用了该函数

#include "stdafx.h"
#include <opencv2\opencv.hpp>
#include <math.h>
#include <iostream>

using namespace cv;
using namespace std;
const int w = 500;

int levels = 3;

vector<vector<Point> > contours;

vector<Vec4i> hierarchy;

void on_trackbar(int, void*)
{
    Mat cnt_img = Mat::zeros(w, w, CV_8UC3);
    int _levels = levels - 3;
    drawContours( cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128,255,255),
            3, CV_AA, hierarchy, std::abs(_levels) );

    imshow("contours", cnt_img);
}

int main( int argc, char**)
{
    Mat img = imread("out.jpg",0);
    threshold(img,img,200,255,cv::THRESH_BINARY);


    namedWindow( "image", 1 );
    imshow( "image", img );
    //Extract the contours so that
    vector<vector<Point> > contours0;
    findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);

    contours.resize(contours0.size());
    for( size_t k = 0; k < contours0.size(); k++ ){
        std::cout<<"contours0.size"<<contours0[k].size()<<endl;
        approxPolyDP(Mat(contours0[k]), contours[k], 0, true);
    }

    std::vector<Vec4i> defects; 
    vector<cv::vector<int> >hull( contours.size() );

    for (int i = 0; i < contours.size(); i++)
    {  
        std::cout<<"contours.size"<<contours[i].size()<<endl;
        convexHull( contours[i], hull[i], false );
        if (contours[i].size() >150 )
        {
            convexityDefects(contours[i], hull[i], defects[i]); 
            std::cout<<"defects"<<defects[i].depth<<endl;
        }
    }


    namedWindow( "contours", 1 );
    createTrackbar( "levels+3", "contours", &levels, 7, on_trackbar );

    on_trackbar(0,0);
    waitKey();

    return 0;
}
#包括“stdafx.h”
#包括
#包括
#包括
使用名称空间cv;
使用名称空间std;
常数int w=500;
智力水平=3;
矢量等值线;
向量层次;
轨迹栏上的void(int,void*)
{
Mat cnt_img=Mat::零(w,w,CV_8UC3);
int_levels=级别-3;

drawContours(cnt\u img,contours,\u levels问题似乎是
凸面缺陷()
需要
轮廓缺陷
参数的数组:

void convexityDefects(InputArray contour, InputArray convexhull, OutputArray convexityDefects);
等高线
船体
都是
向量
类型,这是正确的,但是
缺陷
也需要是
向量
。这样,当您循环通过
等高线
数组时,
缺陷[i]
将包含一个要传递到
凸性缺陷()
的数组:

。。。
矢量缺陷(等高线.size());
...

在以后的代码中,如果您正试图这样做的话,您将不得不循环通过
缺陷[i]
向量来打印
深度

我将在稍后发布一个完整工作源代码的答案,因为我花了太多时间试图找出如何使用此凸面缺陷()API。还请注意,OpenCV 3.0版本中的凸面缺陷()返回了错误的索引(这在OpenCV 2.X中不是问题)。因此,如果您在3.0版本中遇到问题,请更新到最新的github

#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"

// Test case for C++ impl of convexityDefects() that returns indexes into the
// contours vector.

using namespace cv;
using namespace std;

int main(int argc, char **argv)
{
  if (argc != 1) {
    fprintf(stderr, "usage : convexity_defects\n");
    exit(1);
  }

  const bool debugDumpImages = true;

  // Result from findContours(binMat, contours, CV_RETR_LIST, CHAIN_APPROX_NONE);

  // 4 point star pattern at 100x100

  Point2i contour[140];
  contour[0] = Point2i(49,3);
  contour[1] = Point2i(49,7);
  contour[2] = Point2i(48,8);
  contour[3] = Point2i(48,12);
  contour[4] = Point2i(47,13);
  contour[5] = Point2i(47,16);
  contour[6] = Point2i(46,17);
  contour[7] = Point2i(46,21);
  contour[8] = Point2i(45,22);
  contour[9] = Point2i(45,25);
  contour[10] = Point2i(44,26);
  contour[11] = Point2i(44,30);
  contour[12] = Point2i(43,31);
  contour[13] = Point2i(43,35);
  contour[14] = Point2i(42,36);
  contour[15] = Point2i(42,39);
  contour[16] = Point2i(41,40);
  contour[17] = Point2i(41,41);
  contour[18] = Point2i(40,42);
  contour[19] = Point2i(36,42);
  contour[20] = Point2i(35,43);
  contour[21] = Point2i(32,43);
  contour[22] = Point2i(31,44);
  contour[23] = Point2i(27,44);
  contour[24] = Point2i(26,45);
  contour[25] = Point2i(22,45);
  contour[26] = Point2i(21,46);
  contour[27] = Point2i(18,46);
  contour[28] = Point2i(17,47);
  contour[29] = Point2i(13,47);
  contour[30] = Point2i(12,48);
  contour[31] = Point2i(8,48);
  contour[32] = Point2i(7,49);
  contour[33] = Point2i(3,49);
  contour[34] = Point2i(2,50);
  contour[35] = Point2i(1,50);
  contour[36] = Point2i(5,50);
  contour[37] = Point2i(6,51);
  contour[38] = Point2i(10,51);
  contour[39] = Point2i(11,52);
  contour[40] = Point2i(14,52);
  contour[41] = Point2i(15,53);
  contour[42] = Point2i(19,53);
  contour[43] = Point2i(20,54);
  contour[44] = Point2i(24,54);
  contour[45] = Point2i(25,55);
  contour[46] = Point2i(29,55);
  contour[47] = Point2i(30,56);
  contour[48] = Point2i(33,56);
  contour[49] = Point2i(34,57);
  contour[50] = Point2i(38,57);
  contour[51] = Point2i(39,58);
  contour[52] = Point2i(40,58);
  contour[53] = Point2i(42,60);
  contour[54] = Point2i(42,63);
  contour[55] = Point2i(43,64);
  contour[56] = Point2i(43,68);
  contour[57] = Point2i(44,69);
  contour[58] = Point2i(44,73);
  contour[59] = Point2i(45,74);
  contour[60] = Point2i(45,77);
  contour[61] = Point2i(46,78);
  contour[62] = Point2i(46,82);
  contour[63] = Point2i(47,83);
  contour[64] = Point2i(47,87);
  contour[65] = Point2i(48,88);
  contour[66] = Point2i(48,91);
  contour[67] = Point2i(49,92);
  contour[68] = Point2i(49,96);
  contour[69] = Point2i(50,97);
  contour[70] = Point2i(50,93);
  contour[71] = Point2i(51,92);
  contour[72] = Point2i(51,89);
  contour[73] = Point2i(52,88);
  contour[74] = Point2i(52,84);
  contour[75] = Point2i(53,83);
  contour[76] = Point2i(53,80);
  contour[77] = Point2i(54,79);
  contour[78] = Point2i(54,75);
  contour[79] = Point2i(55,74);
  contour[80] = Point2i(55,70);
  contour[81] = Point2i(56,69);
  contour[82] = Point2i(56,66);
  contour[83] = Point2i(57,65);
  contour[84] = Point2i(57,61);
  contour[85] = Point2i(58,60);
  contour[86] = Point2i(58,59);
  contour[87] = Point2i(59,58);
  contour[88] = Point2i(60,58);
  contour[89] = Point2i(61,57);
  contour[90] = Point2i(65,57);
  contour[91] = Point2i(66,56);
  contour[92] = Point2i(70,56);
  contour[93] = Point2i(71,55);
  contour[94] = Point2i(75,55);
  contour[95] = Point2i(76,54);
  contour[96] = Point2i(79,54);
  contour[97] = Point2i(80,53);
  contour[98] = Point2i(84,53);
  contour[99] = Point2i(85,52);
  contour[100] = Point2i(89,52);
  contour[101] = Point2i(90,51);
  contour[102] = Point2i(93,51);
  contour[103] = Point2i(94,50);
  contour[104] = Point2i(98,50);
  contour[105] = Point2i(97,50);
  contour[106] = Point2i(96,49);
  contour[107] = Point2i(92,49);
  contour[108] = Point2i(91,48);
  contour[109] = Point2i(87,48);
  contour[110] = Point2i(86,47);
  contour[111] = Point2i(82,47);
  contour[112] = Point2i(81,46);
  contour[113] = Point2i(78,46);
  contour[114] = Point2i(77,45);
  contour[115] = Point2i(73,45);
  contour[116] = Point2i(72,44);
  contour[117] = Point2i(68,44);
  contour[118] = Point2i(67,43);
  contour[119] = Point2i(64,43);
  contour[120] = Point2i(63,42);
  contour[121] = Point2i(59,42);
  contour[122] = Point2i(58,41);
  contour[123] = Point2i(58,40);
  contour[124] = Point2i(57,39);
  contour[125] = Point2i(57,35);
  contour[126] = Point2i(56,34);
  contour[127] = Point2i(56,31);
  contour[128] = Point2i(55,30);
  contour[129] = Point2i(55,26);
  contour[130] = Point2i(54,25);
  contour[131] = Point2i(54,21);
  contour[132] = Point2i(53,20);
  contour[133] = Point2i(53,17);
  contour[134] = Point2i(52,16);
  contour[135] = Point2i(52,12);
  contour[136] = Point2i(51,11);
  contour[137] = Point2i(51,8);
  contour[138] = Point2i(50,7);
  contour[139] = Point2i(50,3);

  vector<Point2i> contourVec;

  for ( int i = 0; i < sizeof(contour)/sizeof(Point2i); i++ ) {
    Point2i p = contour[i];
    contourVec.push_back(p);
  }

  vector<vector<Point2i> > contoursVec;
  contoursVec.push_back(contourVec);

  if (debugDumpImages) {
    Mat binMat(100, 100, CV_8UC1, Scalar(0));

    drawContours(binMat, contoursVec, 0, Scalar(0xFF));

    string fname = "contour_rendered.png";
    imwrite(fname, binMat);
    cout << "wrote " << fname << endl;
  }

  assert(contourVec.size() > 3);

  // hull around contour points

  Mat contourMat(contourVec);

  vector<int> hullVec;

  convexHull(contourMat, hullVec, false);

  int hullCount = (int)hullVec.size();

  if (1) {
    cout << "convexHull returned " << hullCount << " hull indexes" << endl;
  }

  if (debugDumpImages) {
    // Convert hull indexes into points so that result can be rendered with drawContours()

    vector<Point2i> hullContourVec;

    for ( int i = 0; i < hullCount; i++ ) {
      int offset = hullVec[i];
      Point pt = contourVec[offset];
      hullContourVec.push_back(pt);
    }

    vector<vector<Point2i> > hullContoursVec;
    hullContoursVec.push_back(hullContourVec);

    Mat binMat(100, 100, CV_8UC1, Scalar(0));

    drawContours(binMat, hullContoursVec, 0, Scalar(0xFF));

    string fname = "hull_contour_rendered.png";
    imwrite(fname, binMat);
    cout << "wrote " << fname << endl;
  }

  // calculate convexityDefects()

  vector<Vec4i> defectVec;

  convexityDefects(contourVec, hullVec, defectVec);

  Mat defectBinMat(100, 100, CV_8UC1, Scalar(0));
  Mat colorMat(100, 100, CV_8UC3, Scalar(0,0,0));

  drawContours(colorMat, contoursVec, 0, Scalar(0,0xFF,0), CV_FILLED, 8); // Draw contour as green filled region

  for (int cDefIt = 0; cDefIt < defectVec.size(); cDefIt++) {
    int startIdx = defectVec[cDefIt].val[0];
    int endIdx = defectVec[cDefIt].val[1];
    int defectPtIdx = defectVec[cDefIt].val[2];
    double depth = (double)defectVec[cDefIt].val[3]/256.0f;  // see documentation link below why this

    Point2i startP = contour[startIdx];
    Point2i endP = contour[endIdx];
    Point2i defectP = contour[defectPtIdx];

    printf("start  %8d = (%4d,%4d)\n", startIdx, startP.x, startP.y);
    printf("end    %8d = (%4d,%4d)\n", endIdx, endP.x, endP.y);
    printf("defect %8d = (%4d,%4d)\n", defectPtIdx, defectP.x, defectP.y);
    printf("depth  %0.3f\n", depth);

    if (debugDumpImages) {
      line(defectBinMat, startP, defectP, Scalar(255), 1, 0);
      line(defectBinMat, endP, defectP, Scalar(128), 1, 0);
    }

    line(colorMat, startP, endP, Scalar(0xFF,0,0), 1, 0);
    circle(colorMat, defectP, 4, Scalar(0,0,0xFF), 2);
  }

  if (debugDumpImages) {
    string fname = "hull_contour_defects_rendered.png";
    imwrite(fname, defectBinMat);
    cout << "wrote " << fname << endl;
  }

  if (debugDumpImages) {
    string fname = "contour_defects_rendered.png";
    imwrite(fname, colorMat);
    cout << "wrote " << fname << endl;
  }

  imshow( "defects", colorMat );
  waitKey(0);
}
#包括
#包括“opencv2/highgui/highgui.hpp”
#包括“opencv2/opencv.hpp”
/CurvyDebug()的C++ IMPL的测试用例,将索引返回到
//等高线向量。
使用名称空间cv;
使用名称空间std;
int main(int argc,字符**argv)
{
如果(argc!=1){
fprintf(stderr,“用法:凸面缺陷”);
出口(1);
}
const bool debugDumpImages=true;
//从查找到的结果(binMat、等高线、CV\u RETR\u列表、链\u近似值\u无);
//100x100处的4点星形图案
点2i等高线[140];
等高线[0]=点2i(49,3);
等高线[1]=点2i(49,7);
等高线[2]=点2i(48,8);
等高线[3]=点2i(48,12);
等高线[4]=点2i(47,13);
等高线[5]=点2i(47,16);
等高线[6]=点2i(46,17);
等高线[7]=点2i(46,21);
等高线[8]=点2i(45,22);
等高线[9]=点2i(45,25);
等高线[10]=点2i(44,26);
等高线[11]=点2i(44,30);
等高线[12]=点2i(43,31);
等高线[13]=点2i(43,35);
等高线[14]=点2i(42,36);
等高线[15]=点2i(42,39);
等高线[16]=点2i(41,40);
等高线[17]=点2i(41,41);
等高线[18]=点2i(40,42);
等高线[19]=点2i(36,42);
等高线[20]=点2i(35,43);
等高线[21]=点2i(32,43);
等高线[22]=点2i(31,44);
等高线[23]=点2i(27,44);
等高线[24]=点2i(26,45);
等高线[25]=点2i(22,45);
等高线[26]=点2i(21,46);
等高线[27]=点2i(18,46);
等高线[28]=点2i(17,47);
等高线[29]=点2i(13,47);
等高线[30]=点2i(12,48);
等高线[31]=点2i(8,48);
等高线[32]=点2i(7,49);
等高线[33]=点2i(3,49);
等高线[34]=点2i(2,50);
等高线[35]=点2i(1,50);
等高线[36]=点2i(5,50);
等高线[37]=点2i(6,51);
等高线[38]=点2i(10,51);
等高线[39]=点2i(11,52);
等高线[40]=点2i(14,52);
等高线[41]=点2i(15,53);
等高线[42]=点2i(19,53);
等高线[43]=点2i(20,54);
等高线[44]=点2i(24,54);
等高线[45]=点2i(25,55);
等高线[46]=点2i(29,55);
轮廓[47]=点2i(30,56);
等高线[48]=点2i(33,56);
等高线[49]=点2i(34,57);
等高线[50]=点2i(38,57);
等高线[51]=点2i(39,58);
等高线[52]=点2i(40,58);
等高线[53]=点2i(42,60);
等高线[54]=点2i(42,63);
等高线[55]=点2i(43,64);
等高线[56]=点2i(43,68);
等高线[57]=点2i(44,69);
等高线[58]=点2i(44,73);
等高线[59]=点2i(45,74);
等高线[60]=点2i(45,77);
等高线[61]=点2i(46,78);
等高线[62]=点2i(46,82);
等高线[63]=点2i(47,83);
等高线[64]=点2i(47,87);
等高线[65]=点2i(48,88);
等高线[66]=点2i(48,91);
等高线[67]=点2i(49,92);
等高线[68]=点2i(49,96);
等高线[69]=点2i(50,97);
等高线[70]=点2i(50,93);
等高线[71]=点2i(51,92);
等高线[72]=点2i(51,89);
等高线[73]=点2i(52,88);
等高线[74]=点2i(52,84);
等高线[75]=点2i(53,83);
等高线[76]=点2i(53,80);
等高线[77]=点2i(54,79);
等高线[78]=点2i(54,75);
等高线[79]=点2i(55,74);
等高线[80]=点2i(55,70);
等高线[81]=点2i(56,69);
等高线[82]=点2i(56,66);
等高线[83]=点2i(57,65);
等高线[84]=点2i(57,61);
等高线[85]=点2i(58,60);
等高线[86]=点2i(58,59);
等高线[87]=点2i(59,58);
等高线[88]=点2i(60,58);
等高线[89]=点2i(61,57);
等高线[90]=点2i(65,57);
等高线[91]=点2i(66,56);
等高线[92]=点2i(70,56);
等高线[93]=点2i(71,55);
等高线[94]=点2i(75,55);
等高线[95]=点2i(76,54);
等高线[96]=点2i(79,54);
等高线[97]=点2i(80,53);
等高线[98]=点2i(84,53);
等高线[99]=点2i(85,52);
等高线[100]=点2i(89,52);
等高线[101]=点2i(90,51);
等高线[102]=点2i(93,51);
等高线[103]=点2i(94,50);
等高线[104]=点2i(98,50);
等高线[105]=点2i(97,50);
等高线[106]=点2i(96,49);
等高线[107]=点2i(92,49);
等高线[108]=点2i(91,48);
等高线[109]=点2i(87,48);
等高线[110]=点2i(86,47);
等高线[111]=点2i(82,47);
等高线[112]=点2i(81,46);
等高线[113]=点2i(78,46);
等高线[114]=点2i(77,45);
等高线[115]=点2i(73,45);
骗局
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"

// Test case for C++ impl of convexityDefects() that returns indexes into the
// contours vector.

using namespace cv;
using namespace std;

int main(int argc, char **argv)
{
  if (argc != 1) {
    fprintf(stderr, "usage : convexity_defects\n");
    exit(1);
  }

  const bool debugDumpImages = true;

  // Result from findContours(binMat, contours, CV_RETR_LIST, CHAIN_APPROX_NONE);

  // 4 point star pattern at 100x100

  Point2i contour[140];
  contour[0] = Point2i(49,3);
  contour[1] = Point2i(49,7);
  contour[2] = Point2i(48,8);
  contour[3] = Point2i(48,12);
  contour[4] = Point2i(47,13);
  contour[5] = Point2i(47,16);
  contour[6] = Point2i(46,17);
  contour[7] = Point2i(46,21);
  contour[8] = Point2i(45,22);
  contour[9] = Point2i(45,25);
  contour[10] = Point2i(44,26);
  contour[11] = Point2i(44,30);
  contour[12] = Point2i(43,31);
  contour[13] = Point2i(43,35);
  contour[14] = Point2i(42,36);
  contour[15] = Point2i(42,39);
  contour[16] = Point2i(41,40);
  contour[17] = Point2i(41,41);
  contour[18] = Point2i(40,42);
  contour[19] = Point2i(36,42);
  contour[20] = Point2i(35,43);
  contour[21] = Point2i(32,43);
  contour[22] = Point2i(31,44);
  contour[23] = Point2i(27,44);
  contour[24] = Point2i(26,45);
  contour[25] = Point2i(22,45);
  contour[26] = Point2i(21,46);
  contour[27] = Point2i(18,46);
  contour[28] = Point2i(17,47);
  contour[29] = Point2i(13,47);
  contour[30] = Point2i(12,48);
  contour[31] = Point2i(8,48);
  contour[32] = Point2i(7,49);
  contour[33] = Point2i(3,49);
  contour[34] = Point2i(2,50);
  contour[35] = Point2i(1,50);
  contour[36] = Point2i(5,50);
  contour[37] = Point2i(6,51);
  contour[38] = Point2i(10,51);
  contour[39] = Point2i(11,52);
  contour[40] = Point2i(14,52);
  contour[41] = Point2i(15,53);
  contour[42] = Point2i(19,53);
  contour[43] = Point2i(20,54);
  contour[44] = Point2i(24,54);
  contour[45] = Point2i(25,55);
  contour[46] = Point2i(29,55);
  contour[47] = Point2i(30,56);
  contour[48] = Point2i(33,56);
  contour[49] = Point2i(34,57);
  contour[50] = Point2i(38,57);
  contour[51] = Point2i(39,58);
  contour[52] = Point2i(40,58);
  contour[53] = Point2i(42,60);
  contour[54] = Point2i(42,63);
  contour[55] = Point2i(43,64);
  contour[56] = Point2i(43,68);
  contour[57] = Point2i(44,69);
  contour[58] = Point2i(44,73);
  contour[59] = Point2i(45,74);
  contour[60] = Point2i(45,77);
  contour[61] = Point2i(46,78);
  contour[62] = Point2i(46,82);
  contour[63] = Point2i(47,83);
  contour[64] = Point2i(47,87);
  contour[65] = Point2i(48,88);
  contour[66] = Point2i(48,91);
  contour[67] = Point2i(49,92);
  contour[68] = Point2i(49,96);
  contour[69] = Point2i(50,97);
  contour[70] = Point2i(50,93);
  contour[71] = Point2i(51,92);
  contour[72] = Point2i(51,89);
  contour[73] = Point2i(52,88);
  contour[74] = Point2i(52,84);
  contour[75] = Point2i(53,83);
  contour[76] = Point2i(53,80);
  contour[77] = Point2i(54,79);
  contour[78] = Point2i(54,75);
  contour[79] = Point2i(55,74);
  contour[80] = Point2i(55,70);
  contour[81] = Point2i(56,69);
  contour[82] = Point2i(56,66);
  contour[83] = Point2i(57,65);
  contour[84] = Point2i(57,61);
  contour[85] = Point2i(58,60);
  contour[86] = Point2i(58,59);
  contour[87] = Point2i(59,58);
  contour[88] = Point2i(60,58);
  contour[89] = Point2i(61,57);
  contour[90] = Point2i(65,57);
  contour[91] = Point2i(66,56);
  contour[92] = Point2i(70,56);
  contour[93] = Point2i(71,55);
  contour[94] = Point2i(75,55);
  contour[95] = Point2i(76,54);
  contour[96] = Point2i(79,54);
  contour[97] = Point2i(80,53);
  contour[98] = Point2i(84,53);
  contour[99] = Point2i(85,52);
  contour[100] = Point2i(89,52);
  contour[101] = Point2i(90,51);
  contour[102] = Point2i(93,51);
  contour[103] = Point2i(94,50);
  contour[104] = Point2i(98,50);
  contour[105] = Point2i(97,50);
  contour[106] = Point2i(96,49);
  contour[107] = Point2i(92,49);
  contour[108] = Point2i(91,48);
  contour[109] = Point2i(87,48);
  contour[110] = Point2i(86,47);
  contour[111] = Point2i(82,47);
  contour[112] = Point2i(81,46);
  contour[113] = Point2i(78,46);
  contour[114] = Point2i(77,45);
  contour[115] = Point2i(73,45);
  contour[116] = Point2i(72,44);
  contour[117] = Point2i(68,44);
  contour[118] = Point2i(67,43);
  contour[119] = Point2i(64,43);
  contour[120] = Point2i(63,42);
  contour[121] = Point2i(59,42);
  contour[122] = Point2i(58,41);
  contour[123] = Point2i(58,40);
  contour[124] = Point2i(57,39);
  contour[125] = Point2i(57,35);
  contour[126] = Point2i(56,34);
  contour[127] = Point2i(56,31);
  contour[128] = Point2i(55,30);
  contour[129] = Point2i(55,26);
  contour[130] = Point2i(54,25);
  contour[131] = Point2i(54,21);
  contour[132] = Point2i(53,20);
  contour[133] = Point2i(53,17);
  contour[134] = Point2i(52,16);
  contour[135] = Point2i(52,12);
  contour[136] = Point2i(51,11);
  contour[137] = Point2i(51,8);
  contour[138] = Point2i(50,7);
  contour[139] = Point2i(50,3);

  vector<Point2i> contourVec;

  for ( int i = 0; i < sizeof(contour)/sizeof(Point2i); i++ ) {
    Point2i p = contour[i];
    contourVec.push_back(p);
  }

  vector<vector<Point2i> > contoursVec;
  contoursVec.push_back(contourVec);

  if (debugDumpImages) {
    Mat binMat(100, 100, CV_8UC1, Scalar(0));

    drawContours(binMat, contoursVec, 0, Scalar(0xFF));

    string fname = "contour_rendered.png";
    imwrite(fname, binMat);
    cout << "wrote " << fname << endl;
  }

  assert(contourVec.size() > 3);

  // hull around contour points

  Mat contourMat(contourVec);

  vector<int> hullVec;

  convexHull(contourMat, hullVec, false);

  int hullCount = (int)hullVec.size();

  if (1) {
    cout << "convexHull returned " << hullCount << " hull indexes" << endl;
  }

  if (debugDumpImages) {
    // Convert hull indexes into points so that result can be rendered with drawContours()

    vector<Point2i> hullContourVec;

    for ( int i = 0; i < hullCount; i++ ) {
      int offset = hullVec[i];
      Point pt = contourVec[offset];
      hullContourVec.push_back(pt);
    }

    vector<vector<Point2i> > hullContoursVec;
    hullContoursVec.push_back(hullContourVec);

    Mat binMat(100, 100, CV_8UC1, Scalar(0));

    drawContours(binMat, hullContoursVec, 0, Scalar(0xFF));

    string fname = "hull_contour_rendered.png";
    imwrite(fname, binMat);
    cout << "wrote " << fname << endl;
  }

  // calculate convexityDefects()

  vector<Vec4i> defectVec;

  convexityDefects(contourVec, hullVec, defectVec);

  Mat defectBinMat(100, 100, CV_8UC1, Scalar(0));
  Mat colorMat(100, 100, CV_8UC3, Scalar(0,0,0));

  drawContours(colorMat, contoursVec, 0, Scalar(0,0xFF,0), CV_FILLED, 8); // Draw contour as green filled region

  for (int cDefIt = 0; cDefIt < defectVec.size(); cDefIt++) {
    int startIdx = defectVec[cDefIt].val[0];
    int endIdx = defectVec[cDefIt].val[1];
    int defectPtIdx = defectVec[cDefIt].val[2];
    double depth = (double)defectVec[cDefIt].val[3]/256.0f;  // see documentation link below why this

    Point2i startP = contour[startIdx];
    Point2i endP = contour[endIdx];
    Point2i defectP = contour[defectPtIdx];

    printf("start  %8d = (%4d,%4d)\n", startIdx, startP.x, startP.y);
    printf("end    %8d = (%4d,%4d)\n", endIdx, endP.x, endP.y);
    printf("defect %8d = (%4d,%4d)\n", defectPtIdx, defectP.x, defectP.y);
    printf("depth  %0.3f\n", depth);

    if (debugDumpImages) {
      line(defectBinMat, startP, defectP, Scalar(255), 1, 0);
      line(defectBinMat, endP, defectP, Scalar(128), 1, 0);
    }

    line(colorMat, startP, endP, Scalar(0xFF,0,0), 1, 0);
    circle(colorMat, defectP, 4, Scalar(0,0,0xFF), 2);
  }

  if (debugDumpImages) {
    string fname = "hull_contour_defects_rendered.png";
    imwrite(fname, defectBinMat);
    cout << "wrote " << fname << endl;
  }

  if (debugDumpImages) {
    string fname = "contour_defects_rendered.png";
    imwrite(fname, colorMat);
    cout << "wrote " << fname << endl;
  }

  imshow( "defects", colorMat );
  waitKey(0);
}