void BlockMap::ResetConnectivity() { for (int r = 0; r < Rows(); r++) { for (int c = 0; c < Cols(); c++) { Block& currBlock = m_BlockMatrix[r][c]; // Set reachable neighbors currBlock.neighborOffsets.clear(); Vector2 lOffset(0, -1); Vector2 rOffset(0, 1); Vector2 tOffset(-1, 0); Vector2 bOffset(1, 0); if (ValidCoord(currBlock.coord + lOffset)) currBlock.neighborOffsets.insert(lOffset); if (ValidCoord(currBlock.coord + rOffset)) currBlock.neighborOffsets.insert(rOffset); if (ValidCoord(currBlock.coord + tOffset)) currBlock.neighborOffsets.insert(tOffset); if (ValidCoord(currBlock.coord + bOffset)) currBlock.neighborOffsets.insert(bOffset); } } }
void chilitags::FindQuads::run() { //TODO function too long, split it mQuads.clear(); const cv::Mat tBinaryImage = *mBinaryImage; #ifdef DEBUG_FindQuads cv::RNG tRNG( 0xFFFFFFFF ); cv::Mat tDebugImage = cv::Mat::zeros(cv::Size(2*tBinaryImage.cols, tBinaryImage.rows), CV_8UC3); #endif mScaledCopies[0] = tBinaryImage; for (int i = 1; i < scScaledCopiesCount; ++i) { cv::pyrDown(mScaledCopies[i-1], mScaledCopies[i]); } for (int i = scScaledCopiesCount-1; i>=0; --i) //starting with the lowest definition, so the highest definition are last, and can simply override the first ones. { int tScale = 1 << i; #ifdef DEBUG_FindQuads cv::Point tOffset(tDebugImage.cols-2*mScaledCopies[i].cols,0); cv::Size tScaledSize = mScaledCopies[i].size(); #endif std::vector<std::vector<cv::Point> > contours; cv::findContours(mScaledCopies[i], contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); for (std::vector<std::vector<cv::Point> >::iterator contour = contours.begin(); contour != contours.end(); ++contour) { double tPerimeter = std::abs(cv::arcLength(*contour, true)); double tArea = std::abs(cv::contourArea(*contour)); if (tPerimeter > Quad::scNPoints*scMinTagSize && tArea > scMinTagSize*scMinTagSize) { std::vector<cv::Point> tApproxContour; cv::approxPolyDP( *contour, tApproxContour, tPerimeter*0.02, true); std::vector<cv::Point> tNormalisedContour; cv::convexHull(tApproxContour, tNormalisedContour, false); if (tNormalisedContour.size() == (int) Quad::scNPoints) { Quad tCandidate; tCandidate[0] = tScale*tNormalisedContour[0]; tCandidate[1] = tScale*tNormalisedContour[1]; tCandidate[2] = tScale*tNormalisedContour[2]; tCandidate[3] = tScale*tNormalisedContour[3]; IsSimilarTo tIsSimilarToCandidate(tCandidate); std::vector<Quad>::iterator tSameQuad = std::find_if( mQuads.begin(), mQuads.end(), tIsSimilarToCandidate); if (false && tSameQuad != mQuads.end()) // TODO move to Decode { *tSameQuad = tCandidate; #ifdef DEBUG_FindQuads drawContour(tDebugImage, tNormalisedContour, cv::Scalar(0,255,255), tOffset); #endif } else { mQuads.push_back(tCandidate); #ifdef DEBUG_FindQuads drawContour(tDebugImage, tNormalisedContour, cv::Scalar(0,255,0), tOffset); #endif } } #ifdef DEBUG_FindQuads else // not quadrilaterals { drawContour(tDebugImage, tNormalisedContour, cv::Scalar(0,0,255), tOffset); } #endif } #ifdef DEBUG_FindQuads else // too small { drawContour(tDebugImage, *contour, cv::Scalar(128,128,128), tOffset); } #endif } #ifdef DEBUG_FindQuads cv::putText(tDebugImage, cv::format("%d", contours.size()), tOffset+cv::Point(32,32), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar::all(255)); #endif } #ifdef DEBUG_FindQuads cv::imshow("FindQuads", tDebugImage); cv::waitKey(0); #endif }