この凸性欠陥 () API の使用方法を理解するのに時間がかかりすぎたため、後で完全に機能するソース コードを含む回答を投稿します。また、OpenCV 3.0 リリースには、convexityDefects() にバグが含まれており、間違ったインデックスが返されていたことにも注意してください (これは 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);
}