Избегайте пересчета контуров на холсте OpencvC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Избегайте пересчета контуров на холсте Opencv

Сообщение Anonymous »

У меня есть программа распознавания контуров в Opencv, где пользователь рисует каракули на холсте (белом), а затем находит его контуры, аппроксимирует их в многоугольник и показывает синими линиями.
Текущий пример ввода:
Изображение

< р>Текущий пример вывода:
Изображение

Одна из проблем, с которой я столкнулся в текущей реализации, заключается в том, что синие контурные линии начинают выглядеть странно и толсто, как только я добавляю новые каракули одну за другой. Это означает, что предыдущие каракули будут пересчитываться снова и снова каждый раз, когда я добавляю новую каракули, в результате чего синяя контурная линия становится все толще и толще, поскольку программа не распознает, что контур для этих предыдущих каракулей уже был нарисован. Поэтому только последняя нарисованная каракуля выглядит так, как хотелось:
Изображение
< /p>
Вот мой код:

Код: Выделить всё

ScribbleWidget::ScribbleWidget(QWidget *parent)
: QLabel(parent), _drawing(false), _penWidth(20) {
_canvas = cv::Mat::zeros(600, 800, CV_8UC3);
_canvas.setTo(cv::Scalar(255, 255, 255));
updateDisplay(); // initially shows a white empty canvas
}

void ScribbleWidget::setCanvas(const cv::Mat &newCanvas) { //  update the canvas
_canvas = newCanvas.clone();
updateDisplay();
}
cv::Mat ScribbleWidget::generateContours(const cv::Mat &inputImage, int threshold) {
cv::Mat gray, edges, contourImage;

//  convert the input image to grayscale, to simplify the process of detecting edges and contours
cv::cvtColor(inputImage, gray, cv::COLOR_BGR2GRAY);

// apply Canny edge detection
cv::Canny(gray, edges, threshold, threshold * 2); // NOTE: treshold controls the detection sensitivity (higher value = fewer detected edges)

// Find contours (including hierarchy for holes)
std::vector contours; // Contours are stored as a list of points
std::vector hierarchy; // 4-element vector of integers used to store four integer values in a single structure representing the hierarchical relationships between contours
// !!! Values for Vec4i:
//  [0] (Next contour): Index of the next contour at the same hierarchical level. If there is no next contour, it is set to -1.
//  [1] (Previous contour): Index of the previous contour at the same hierarchical level. If there is no previous contour, it is set to -1.
//  [2] (First child contour): Index of the first child contour (a contour nested inside the current contour). If there are no child contours, it is set to -1.
//  [3] (Parent contour): Index of the parent contour (the contour that contains the current contour).  If there is no parent (i.e., the contour is at the outermost level), it is set to -1.

cv::findContours(edges, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE); // NOTE: RETR_TREE finds all contours and includes information about nested contours (holes).

// clone of the original image that will be used to draw the contours as output
contourImage = inputImage.clone();

// Approximate contours using the Douglas-Peucker algorithm
for (size_t i = 0; i < contours.size(); ++i) {
std::vector approxPolygon;
double epsilon = 0.002 * cv::arcLength(contours[i], true); // Adjust epsilon for simplification
cv::approxPolyDP(contours[i], approxPolygon, epsilon, true); // approximate the contours to polygons

// Draw the approximated polygon in blue
cv::polylines(contourImage, std::vector{approxPolygon}, true, cv::Scalar(255, 0, 0), 2);
}

return contourImage; // Contains the drawn contours
}

void ScribbleWidget::mousePressEvent(QMouseEvent *event) { // drawing begins
if (event->button() == Qt::LeftButton) {
_drawing = true;
_lastPoint = event->pos(); // record the starting point
}
}

void ScribbleWidget::mouseMoveEvent(QMouseEvent *event)  { // lines are drawn on the canvas upon movement
if (_drawing && (event->buttons() & Qt::LeftButton)) {
cv::Point currentPoint(event->pos().x(), event->pos().y());

// draw a line from the last point to the current point ( Scalar = line color, LINE_AA = Anti-aliasing)
cv::line(_canvas, cv::Point(_lastPoint.x(), _lastPoint.y()), currentPoint, cv::Scalar(0, 0, 0), _penWidth, cv::LINE_AA);
_lastPoint = event->pos(); //  update lastPoint to the current mouse position
updateDisplay(); // refresh the image shown on the widget
}
}

void ScribbleWidget::mouseReleaseEvent(QMouseEvent *event) { // drawing stops
if (event->button() == Qt::LeftButton) {
_drawing = false;
emit drawingFinished(_canvas); // pass the current canvas to MainWindow to process further with generate contours
}
}

Код: Выделить всё

MainWindow:

Код: Выделить всё

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);

auto *widget = new QWidget(this);
auto *layout = new QVBoxLayout(widget);
setCentralWidget(widget);

_scribbleWidget = new ScribbleWidget(this); // This is the area where the user can draw
layout->addWidget(_scribbleWidget);

QObject::connect(_scribbleWidget, &ScribbleWidget::drawingFinished, this, &MainWindow::onDrawingFinished); // When mouse button has been released, the drawing is finished too
}

void MainWindow::onDrawingFinished(const cv::Mat &image) { // image is the drawing
cv::Mat contourImage = _scribbleWidget->generateContours(image, 50); // the drawn scribble image is passed so its contour is traced
_scribbleWidget->setCanvas(contourImage); // The updated canvas (containing the contours) is back on the widget
}

Есть ли способ избежать пересчета предыдущих каракулей? Я новичок в Opencv, поэтому я ценю простые инструкции и, в идеале, фрагменты кода в качестве помощи :)
Спасибо всем!

Подробнее здесь: https://stackoverflow.com/questions/792 ... vas-opencv
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»