Oh.. and the source:
(Will not compile out of the box, but you should be able to fix it up).
typedef std::pair<uint, uint> CellIndex;bool getNeighborCellIndex(CellIndex& neighborIndex, const CellIndex& cellIndex, const uint direction, const uint w, const uint h){ static const int directions[4][2] = { 0, -1, 1, 0, 0, 1, -1, 0, }; neighborIndex.first = cellIndex.first + directions[direction][0]; if (neighborIndex.first >= w) return false; neighborIndex.second = cellIndex.second + directions[direction][1]; if (neighborIndex.second >= h) return false; return true;}void traceContour(std::vector<CellIndex>& contour, const Image* const im, const uint x, const uint y, const uint w, const uint h, const uint p){ CellIndex cellIndex = CellIndex(x, y); contour.push_back(cellIndex); uint oldDirection = 0; CellIndex firstCellIndex = cellIndex; for (; ; ){ uint testDirection; CellIndex testCellIndex; uint i; for (i = 1; i < 4; ++ i){ testDirection = (oldDirection + i) & 3; if (getNeighborCellIndex(testCellIndex, cellIndex, testDirection, w, h)){ uint pp; im->getIndex(testCellIndex.first, testCellIndex.second, pp); if (pp == p) break; } } if (i == 4){ // We're on single side that has no other connected neighbors than the previous one. So we must step back on the same cell. if (cellIndex == firstCellIndex) break; // found a complete path of a single cell testDirection = oldDirection; if (!getNeighborCellIndex(testCellIndex, cellIndex, testDirection, w, h)) break; // Should never happen! } if (testCellIndex == firstCellIndex) break; // Found a complete path cellIndex = testCellIndex; // Update current cell index oldDirection = (testDirection + 2) & 3; // Swicth direction from "going to" to "coming from" contour.push_back(cellIndex); }}bool getNeighborCellIndexDiag(CellIndex& neighborIndex, const CellIndex& cellIndex, const uint direction, const uint w, const uint h){ static const int directions[8][2] = { 0, -1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, -1, 0, -1, -1, }; neighborIndex.first = cellIndex.first + directions[direction][0]; if (neighborIndex.first >= w) return false; neighborIndex.second = cellIndex.second + directions[direction][1]; if (neighborIndex.second >= h) return false; return true;}void traceContourDiag(std::vector<CellIndex>& contour, const Image* const im, const uint x, const uint y, const uint w, const uint h, const uint p){ CellIndex cellIndex = CellIndex(x, y); contour.push_back(cellIndex); uint oldDirection = 0; CellIndex firstCellIndex = cellIndex; for (; ; ){ uint testDirection; CellIndex testCellIndex; uint i; for (i = 1; i < 8; ++ i){ testDirection = (oldDirection + i) & 7; if (getNeighborCellIndexDiag(testCellIndex, cellIndex, testDirection, w, h)){ uint pp; im->getIndex(testCellIndex.first, testCellIndex.second, pp); if (pp == p) break; } } if (i == 8){ // We're on single side that has no other connected neighbors than the previous one. So we must step back on the same cell. if (cellIndex == firstCellIndex) break; // found a complete path of a single cell testDirection = oldDirection; if (!getNeighborCellIndexDiag(testCellIndex, cellIndex, testDirection, w, h)) break; // Should never happen! } if (testCellIndex == firstCellIndex) break; // Found a complete path cellIndex = testCellIndex; // Update current cell index oldDirection = (testDirection + 4) & 7; // Swicth direction from "going to" to "coming from" contour.push_back(cellIndex); }}