#include "ContourAnalyzer.h" #include #include "../UI.h" #include ContourAnalyzer::ContourAnalyzer(UI *ui, int *lastKey) { ContourAnalyzer::ui = ui; ui->UIListeners.push_back(this); this->lastKey = lastKey; } void ContourAnalyzer::analyze() { preAnalyze(); cv::cvtColor(*(ui->currentFrame(-1)), *(ui->nextFrame()), cv::COLOR_BGR2GRAY); cv::GaussianBlur(*(ui->currentFrame(-1)), *(ui->nextFrame()), cv::Size(5, 5), 0); cv::threshold(*(ui->currentFrame(-1)), *(ui->nextFrame()), binLower, 255, cv::THRESH_BINARY); cv::Canny(*(ui->currentFrame(-1)), *(ui->nextFrame()), cannyLower, cannyUpper); cv::findContours(*(ui->currentFrame()), contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); removeRedundancy(); if (drawContours) { drawContoursOntoMat(*(ui->drawnFrame())); cv::putText(*(ui->drawnFrame()), "Showing possible triangles rectangles.", cv::Point{5, 30}, cv::FONT_HERSHEY_PLAIN, 0.8, selectColor); } } void ContourAnalyzer::analyze(cv::Rect rect) { preAnalyze(); cv::Mat frame; ui->getOriginalFrame().copyTo(frame); cv::Mat cropped = frame(rect); cv::cvtColor(cropped, cropped, cv::COLOR_BGR2GRAY); cv::GaussianBlur(cropped, cropped, cv::Size(5, 5), 0); cv::threshold(cropped, cropped, binLower, 255, cv::THRESH_BINARY); cv::Canny(cropped, cropped, cannyLower, cannyUpper); cv::findContours(cropped, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); removeRedundancy(); } void ContourAnalyzer::removeRedundancy() { for (unsigned i = 0; i < contours.size(); i++) { if ((cv::contourArea(contours[i]) > minSize) && (cv::contourArea(contours[i]) < (ui->currentFrame(0)->cols * ui->currentFrame(0)->rows) -25)) { double perimeter = cv::arcLength(contours[i], true); cv::approxPolyDP(contours[i], contours[i], (epsilon/(float)1000)*perimeter, true); if ((contours[i].size() == 4) && (cv::isContourConvex(contours[i]))) { if (prunedContours.size() != 0) { bool different = true; for (unsigned comparedTo = 0; comparedTo < prunedContours.size(); comparedTo++) { cv::Moments m1 = cv::moments(prunedContours[comparedTo]); int cx1 = (m1.m10/m1.m00); int cy1 = (m1.m01/m1.m00); cv::Moments m2 = cv::moments(contours[i]); int cx2 = (m2.m10/m2.m00); int cy2 = (m2.m01/m2.m00); if ((std::abs(cx1 - cx2) < 3) && (std::abs(cy1 - cy2) < 3)) { different = false; break; } } if (different) { prunedContours.insert(prunedContours.begin(), contours[i]); } } else { prunedContours.insert(prunedContours.begin(), contours[i]); } } } } } void ContourAnalyzer::preAnalyze() { prunedContours.clear(); if (*lastKey == 99) { cannyRec = !cannyRec; } else if (*lastKey == 118) { drawContours = !drawContours; } minSize = ui->getWidth()*ui->getHeight()*(minSizeScale/(float)10000); if (cannyRec) { cannyUpper = std::min(3*cannyLower, 255); cv::setTrackbarPos("Can. Upper", UI::DEBUG_WINDOW, cannyUpper); } } void ContourAnalyzer::drawContoursOntoMat(cv::Mat &frame) { for (unsigned i = 0; i < prunedContours.size(); i++) { cv::drawContours(frame, prunedContours, i, selectColor, 1); } } void ContourAnalyzer::convertContoursToBounds() { bounds.clear(); for (unsigned i = 0; i < prunedContours.size(); i++) { bounds.push_back(cv::boundingRect(prunedContours[i])); } } std::string ContourAnalyzer::contourToString(std::vector contour) { switch (contour.size()) { case 4: if (cv::isContourConvex(contour)) { return "rectangle"; } /* no break */ default: throw std::invalid_argument("Shape too complex!"); } } std::vector ContourAnalyzer::getBounds() const { return bounds; } void ContourAnalyzer::componentSetup() { cv::createTrackbar("Bin. Lower", UI::DEBUG_WINDOW, &binLower , 255); cv::createTrackbar("Can. Lower", UI::DEBUG_WINDOW, &cannyLower , 255); cv::createTrackbar("Can. Upper", UI::DEBUG_WINDOW, &cannyUpper , 255); cv::createTrackbar("Epsilon", UI::DEBUG_WINDOW, &epsilon , 1000); cv::createTrackbar("Min. Size", UI::DEBUG_WINDOW, &minSizeScale, 10000); } ContourAnalyzer::~ContourAnalyzer() { ui->UIListeners.erase(std::remove(ui->UIListeners.begin(), ui->UIListeners.end(), this)); }