LedMeasurement augmentKeypoint(cv::Mat grayImage, cv::KeyPoint origKeypoint) { // Saving this now before we monkey with m_floodFillMask cv::bitwise_not(m_floodFillMask, m_scratchNotMask); const int loDiff = 2; const int upDiff = 2; auto m_area = cv::floodFill( grayImage, m_floodFillMask, origKeypoint.pt, 255, &m_filledBounds, loDiff, upDiff, CV_FLOODFILL_MASK_ONLY | (/* connectivity 4 or 8 */ 4) | (/* value to write in to mask */ 255 << 8)); // Now m_floodFillMask contains the mask with both our point // and all other points so far. We need to split them by ANDing with // the NOT of the old flood-fill mask we saved earlier. cv::bitwise_and(m_scratchNotMask, m_floodFillMask, m_perPointResults); // OK, now we have the results for just this point in per-point // results /// Initialize return value auto ret = static_cast<LedMeasurement>(origKeypoint); if (m_area <= 0) { // strange... return ret; } m_binarySubImage = m_perPointResults(m_filledBounds); computeContour(); m_moments = haveContour() ? cv::moments(m_contour, false) : cv::moments(m_binarySubImage, true); // the first two we are using from the keypoint description, the latter we can't // always get (contour-based) #if 0 /// Estimate diameter ret.diameter = diameter(); ret.area = area(); if (haveContour()) { ret.circularity = circularity(); } #endif ret.knowBoundingBox = true; ret.boundingBox = cv::Size2f(m_filledBounds.width, m_filledBounds.height); return ret; }
double circularity(Mat& src, int obj_id) { vector<Point> object = foreground(src, obj_id); return circularity(object); }