Результат обнаружения контура фрагментирован, если он не закрыт.C++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Результат обнаружения контура фрагментирован, если он не закрыт.

Сообщение Anonymous »

У меня есть проект Qt, использующий opencv и C++. Это программа обнаружения контуров, которая обнаруживает контуры нарисованных от руки каракулей, приближает их к многоугольнику и отображает результат на второй этикетке. Есть родительские и дочерние контуры. Если у контура нет дочерних элементов, то это родительский контур без отверстий. Если у родителя есть дочерние контуры, это означает, что он содержит дыры.
Моя проблема в том, что если контур открыт (то есть у родителя нет дочерних элементов), выходные данные имеют фрагментированный посмотрите, как будто некоторые моменты не правильно распознаны. Я проверяю, что аргументы «isClosed» и т. д. установлены правильно в зависимости от того, закрыт контур или нет. Но проблема остается.
Изображение

Как видите, слева находится ввод, представляющий собой черную нарисованную от руки каракулю. Когда мышь отпущена, контуры рисунка (еще не приближенные к многоугольнику) отображаются вокруг фигур в виде синих контуров (выходные данные по желанию). В правой части показаны аппроксимированные многоугольники нарисованных фигур (тоже выходные данные). Как видите, замкнутый контур, похожий на цифру «8», отображается именно так, как хотелось бы, а вот остальные три «открытых» контура показаны в виде обрезанных линий, фрагментированы.
Основываясь на том, что я исследовал до сих пор, все, что я получил в качестве ответа, это либо манипулировать значением эпсилона, превращая его в нечто большее ИЛИ меньше, либо изменить пороговое значение. Мне ничего не помогло.
Вот мой класс opencv, который определяет контур (ScribbleWidget):

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

// priv
class ScribbleWidgetPriv
{
friend ScribbleWidget;

public:
explicit ScribbleWidgetPriv(ScribbleWidget* widget);
~ScribbleWidgetPriv();

QPair separateParentChildPaths(const std::vector& contours, const std::vector& hierarchy);

signals:
void mapExtracted(std::map contourMap);

private:
ScribbleWidget* _widget = nullptr;
cv::Mat _canvas;
QPoint _lastPoint;
};

ScribbleWidgetPriv::ScribbleWidgetPriv(ScribbleWidget* widget)
{
_widget = widget;
}

ScribbleWidgetPriv::~ScribbleWidgetPriv()
{

}
// end of priv

ScribbleWidget::ScribbleWidget(QWidget *parent)
: QLabel(parent), _drawing(false), _penWidth(20)
{
_priv = new ScribbleWidgetPriv(this);
_priv->_canvas = cv::Mat::zeros(600, 800, CV_8UC3);
_priv->_canvas.setTo(cv::Scalar(255, 255, 255));  // Initialize the drawing canvas as white
updateDisplay();  // Initially shows a white empty canvas
}

void ScribbleWidget::mousePressEvent(QMouseEvent *event) {
if ( event->button() == Qt::LeftButton ) {
_drawing = true;
_priv->_lastPoint = event->pos();
}
}

void ScribbleWidget::mouseMoveEvent(QMouseEvent *event) {
if ( _drawing && (event->buttons() & Qt::LeftButton) ) {
cv::Point currentPoint(event->pos().x(), event->pos().y());
cv::line(_priv->_canvas, cv::Point(_priv->_lastPoint.x(), _priv->_lastPoint.y()), currentPoint, cv::Scalar(0, 0, 0), _penWidth, cv::LINE_AA);
_priv->_lastPoint = event->pos();
updateDisplay();
}
}

void ScribbleWidget::mouseReleaseEvent(QMouseEvent *event) {
if ( event->button() == Qt::LeftButton ) {
_drawing = false;
emit drawingFinished(_priv->_canvas);  // Pass the current canvas to MainWindow
}
}

void ScribbleWidget::updateDisplay() {
QImage displayImage(_priv->_canvas.data, _priv->_canvas.cols, _priv->_canvas.rows, _priv->_canvas.step, QImage::Format_RGB888);
setPixmap(QPixmap::fromImage(displayImage.rgbSwapped()));
}

cv::Mat ScribbleWidget::generateContoursAndOverlay(const cv::Mat &inputImage, int threshold) {
cv::Mat gray, edges, contourImage, resultImage;

// Convert the input image to grayscale
cv::cvtColor(inputImage, gray, cv::COLOR_BGR2GRAY);

// Apply Canny edge detection
cv::Canny(gray, edges, threshold, threshold * 2);

// Create an empty canvas for contours (ensure the result canvas is blank)
contourImage = cv::Mat::zeros(inputImage.size(), CV_8UC3);  // Blank canvas for contours

// Find contours and hierarchy
std::vector contours;
std::vector hierarchy;
cv::findContours(edges, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

// for QPainterPath:
QPair paths = _priv->separateParentChildPaths(contours, hierarchy);

organizeContours(contours, hierarchy);

// Create a result canvas by copying the original image (which is the drawing)
resultImage = inputImage.clone();

// Iterate through contours and approximate polygons
for (size_t i = 0; i < contours.size(); ++i) {
std::vector approxPolygon;

// Check if the contour is closed or open based on the hierarchy
bool isClosed = (hierarchy[i][2] != -1);

double epsilon = isClosed ? 0.002 * cv::arcLength(contours[i], true)
: 0.001 * cv::arcLength(contours[i], false);

cv::approxPolyDP(contours[i], approxPolygon, epsilon, isClosed);

// Draw the approximated polygon (only the contour lines)
cv::polylines(contourImage, std::vector{approxPolygon}, isClosed, cv::Scalar(255, 0, 0), 4);
}
cv::addWeighted(resultImage, 1.0, contourImage, 1.0, 0.0, resultImage);  // Overlay contours on top

return resultImage;

QPair  ScribbleWidgetPriv::separateParentChildPaths(const std::vector& contours, const std::vector& hierarchy)
{
QList parentPaths;
QList childPaths;

for ( size_t i = 0; i < contours.size(); ++i ) {
// Convert the current contour to a QPainterPath
const auto& contour = contours[i];
QPainterPath path;

if ( !contour.empty() ) {
path.moveTo(contour[0].x, contour[0].y);

for ( size_t j = 1; j < contour.size(); ++j ) {
path.lineTo(contour[j].x, contour[j].y);
}

path.closeSubpath();
}

// Use hierarchy to classify as parent or child
if ( hierarchy[i][3] == -1 ) {
// No parent, so it's a top-level (parent) contour
parentPaths.append(path);
}
else {
// Has a parent, so it's a nested (child) contour
childPaths.append(path);
}
}

return {parentPaths, childPaths};
}

QPainterPath ScribbleWidget::contourToPainterPath( const std::vector& contour )
{

QPainterPath path;

if (!contour.empty()) {
path.moveTo(contour[0].x, contour[0].y);

// Add all the points in the contour
for (size_t i = 1; i < contour.size(); ++i) {
path.lineTo(contour[i].x, contour[i].y);
}

// Check if the contour is closed (first and last points are the same)
bool isClosed = (contour[0] == contour[contour.size() - 1]);

// Only close the path if it's a closed contour
if (isClosed) {
path.closeSubpath(); // Close the path explicitly if it’s closed
}
}

return path;
}

void ScribbleWidget::organizeContours(
const std::vector& contours,
const std::vector& hierarchy)
{
std::map contourMap;

for (size_t i = 0; i < hierarchy.size(); ++i) {
const cv::Vec4i& h = hierarchy[i];
int parentIdx = h[3]; // The index of the parent contour
std::vector approxPolygon;
bool hasChildren = (h[2] != -1); // Check if the contour has children
bool isClosed = hasChildren; // Treat contours with children as closed

// Adjust epsilon for open vs closed contours
double epsilon = isClosed ? 0.002 * cv::arcLength(contours[i], true)
: 0.001 * cv::arcLength(contours[i], false);

// Approximate polygon based on open or closed status
if (isClosed) {
cv::approxPolyDP(contours[i], approxPolygon, epsilon, true);
} else {

// Approximate the smoothed open contour
cv::approxPolyDP(contours[i], approxPolygon, epsilon, false);
}

QPainterPath currentPath;
QPolygonF polygon;

for (const auto& pt : approxPolygon) {
polygon 

Подробнее здесь: [url]https://stackoverflow.com/questions/79335838/contour-detection-result-is-fragmented-if-not-closed[/url]
Реклама
Ответить Пред. темаСлед. тема

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Результат обнаружения контура фрагментирован, если он не закрыт.
    Anonymous » » в форуме C++
    0 Ответы
    22 Просмотры
    Последнее сообщение Anonymous
  • Результат обнаружения контура фрагментирован, если он не закрыт.
    Anonymous » » в форуме C++
    0 Ответы
    10 Просмотры
    Последнее сообщение Anonymous
  • Результат обнаружения контура фрагментирован, если он не закрыт.
    Anonymous » » в форуме C++
    0 Ответы
    20 Просмотры
    Последнее сообщение Anonymous
  • Результат обнаружения контура фрагментирован, если он не закрыт.
    Anonymous » » в форуме C++
    0 Ответы
    18 Просмотры
    Последнее сообщение Anonymous
  • Предупреждение о производительности: DataFrame сильно фрагментирован. Обычно это результат многократного вызова `frame.i
    Anonymous » » в форуме Python
    0 Ответы
    21 Просмотры
    Последнее сообщение Anonymous

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