/* * Filter for L-shaped contours */ void PlaygroundDetector::filterContours(const Contours &contours, Contours &filteredContours) const { filteredContours.clear(); for(unsigned i=0; i<contours.size(); i++) { if(contours[i].size() > 5) { double area = cv::contourArea(contours[i]); if(area > 100 && area < 3000) { // smooth contour std::vector<cv::Point> approxCurve; cv::approxPolyDP(contours[i], approxCurve, double ( contours[i].size() ) *0.025 , true ); if(approxCurve.size() != 6) continue; std::vector<cv::Point> hull; cv::convexHull(approxCurve, hull); float convexity = area / cv::contourArea(hull); if(convexity > 0.3f && convexity < 0.7f && hull.size() == 5) { filteredContours.push_back(approxCurve); //std::cout << "Area:" << area << " Convexity:" << convexity << std::endl; } } } } }
cv::Mat connectedComponentsFilter(cv::Mat& curFrame, cv::Mat& img) { if (!img.isContinuous()) { throwError("Parammeter 'img' in 'connectedComponentsFilter' must be continuous"); } //morphology_(img); maskContours.clear(); // Отрисовать найденные области обратно в маску cv::Mat result(img.size(), img.type()); result.setTo(0); cv::findContours(img, maskContours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); size_t i = 0; while (i < maskContours.size()) { Contour& contour = maskContours[i]; cv::Mat contourMat(contour, false); double len = cv::arcLength(contourMat, true); if (len * PERIM_SCALE < img.size().height + img.size().width) { // Отбрасываем контуры со слишком маленьким периметром. maskContours.erase(maskContours.begin() + i); } else { // Достаточно большие контуры аппроксимируем указанным методом. Contour newContour; // Методы аппроксимации. //cv::approxPolyDP(contourMat, newContour, CHAIN_APPROX_SIMPLE, true); cv::convexHull(contourMat, newContour, true); cv::Mat newContourMat(newContour, false); Rect boundingRect = cv::boundingRect(newContourMat); cv::rectangle(curFrame, boundingRect, cv::Scalar(255)); maskContours[i] = newContour; i++; //points.push_back(CvPoint(boundingRect.x + boundingRect.width / 2, boundingRect.y + boundingRect.height / 2)); } } if (!maskContours.empty()) { // Обходим баг OpenCV 2.1.0; в 2.3.1 он уже исправлен. cv::drawContours(result, maskContours, -1, cv::Scalar(255), FILLED); } return result; }
void Calibration::Start() { Utility::Logger* logger = Utility::Logger::GetInstance(); logger->SetFileLoggingState(false); logger->Log(Utility::Logger::LOG_MESSAGE, "Calibration: Welcome to the camera calibration! Please hold an odd checkerboard or KB-06 techboard in front of the camera. Press G to start the calibration!"); // Return empty if this isn't open if (!m_settings->GetIsOpenedAndGood()) { return; } const char KEY_ESC = 27; const char KEY_U = 'u'; const char KEY_G = 'g'; State mode = m_settings->GetInputType() == CalibrationSettings::InputType::IMAGE_LIST ? State::CAPTURING : State::DETECTION; cv::Size imageSize; cv::Mat cameraMatrix; cv::Mat distortionCoefficients; Contours contours; char key; bool isRunning = true; clock_t timestamp = 0; while (isRunning) { cv::Mat image; FetchNextImage(image); if (!image.empty()) { bool blinkOutput = false; imageSize = image.size(); if (m_settings->GetInputFlipHorizontal()) { cv::flip(image, image, 0); } if (mode == State::CAPTURING && contours.size() >= static_cast<unsigned int>(m_settings->GetNumberOfFrames())) { if (RunAndSaveCalibration(imageSize, cameraMatrix, distortionCoefficients, contours)) { mode = State::CALIBRATED; } else { mode = State::DETECTION; } } bool found = false; Corners corners; switch (m_settings->GetCalibrationPattern()) { case CalibrationSettings::Pattern::CHESSBOARD: found = cv::findChessboardCorners(image, m_settings->GetBoardSize(), corners, (CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE)); break; case CalibrationSettings::Pattern::CIRCLES_GRID: found = cv::findCirclesGrid(image, m_settings->GetBoardSize(), corners); break; case CalibrationSettings::Pattern::ASYMMETRIC_CIRCLES_GRID: found = cv::findCirclesGrid(image, m_settings->GetBoardSize(), corners, CALIB_CB_ASYMMETRIC_GRID); break; } if (found) { // improve the found corners' coordinate accuracy for chessboard if (m_settings->GetCalibrationPattern() == CalibrationSettings::Pattern::CHESSBOARD) { cv::Mat gray; cv::cvtColor(image, gray, CV_BGR2GRAY); cv::cornerSubPix(gray, corners, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); } // For camera only take new samples after delay time if (mode == State::CAPTURING && ((clock() - timestamp) > (m_settings->GetInputDelay() * 1e-3 * CLOCKS_PER_SEC))) { contours.push_back(corners); blinkOutput = m_capture.isOpened(); // Up the current frame m_currentFrame++; } // Draw the corners. cv::drawChessboardCorners(image, m_settings->GetBoardSize(), cv::Mat(corners), found); } // Check if we need to blink output if (blinkOutput) { cv::bitwise_not(image, image); } // Check if we can undistort output if (mode == State::CALIBRATED && m_settings->GetShowUndistortedImage()) { cv::undistort(image.clone(), image, cameraMatrix, distortionCoefficients); } // Show image cv::imshow("TEST", image); // Delay + capture key key = static_cast<char>(cv::waitKey(m_capture.isOpened() ? 50 : m_settings->GetInputDelay())); // Check for esc key if (key == KEY_ESC) { isRunning = false; } // Check for u key else if (key == KEY_U) { m_settings->SetShowUndistortedImage(!m_settings->GetShowUndistortedImage()); } // Check for k key else if (key == KEY_G && m_capture.isOpened()) { mode = State::CAPTURING; contours.clear(); } } else { if (contours.size() > 0) { RunAndSaveCalibration(imageSize, cameraMatrix, distortionCoefficients, contours); isRunning = false; } } } }