Почему opencv находит пограничные точки контуров неупорядоченными и незавершенными?

#c #c #opencv #contour

#c #c #opencv #контур

Вопрос:

Я хочу написать программу, которая может исправить таблицу ответов с помощью opencv на C .

Но, поскольку я использую cvFindContours() , пограничные точки контуров не были полностью найдены.

Я имею в виду, у меня нет закрытых объектов. (Я использую cvDilate и cvErode , не зная их реальной функциональности, но dilate опускает некоторые контуры и erode добавляет некоторые дополнительные, нежелательные контуры)

И большая проблема в том, что я хочу найти центральную точку в каждом контуре (чтобы сравнить расположение ответов с предопределенными левыми и нижними боковыми панелями), но некоторые контуры не симметричны, поэтому расположение центральной точки находится не точно посередине.

Посмотрите на черное изображение слева, во втором контуре, некоторые из нижних точек обнаружены, но верхние не обнаружены.

Это лист ответов:

Первые 8 ответов

 cvCvtColor(pic, blackpic, CV_BGR2GRAY);
cvResize(blackpic, src0);
cvSmooth(src0, src0, CV_GAUSSIAN, 3, 3);
cvThreshold(src0, src, 140, 255, CV_THRESH_BINARY);


//Find Contour
CvMemStorage* st = cvCreateMemStorage();
CvSeq* first_contour = NULL;
cvFindContours(src, st, amp;first_contour, sizeof(CvContour), CV_RETR_LIST);

vector <vector <CvPoint> > cont;
vector <CvPoint> dot;

for (CvSeq* s = first_contour; s != NULL; s = s->h_next)
    if (s -> total > C_MIN_SIZE amp;amp; cvContourArea(s) > C_MIN_AREA)
    {
        cont.push_back(vector <CvPoint>()); //convert seq to vector
        CvPoint c = cvPoint(0,0);
        for (int i = 0; i < s -> total; i  )
        {
            CvPoint* p = CV_GET_SEQ_ELEM(CvPoint, s, i);
            cont.back().push_back(*p);
            CV_IMAGE_ELEM(test, uchar, p -> y, p -> x) = 255; //drawing each contour's point
            c.x  = p -> x; //find the center point by average
            c.y  = p -> y;
        }
        c.x = floor(c.x / s -> total);
        c.y = floor(c.y / s -> total);
        dot.push_back(c);
    }
  
  • Хотя я использую C , но я использую IplImage * и CvPoint (структуры c для opencv) вместо cv::Mat и cv::Point (структуры C ), если это возможно, пожалуйста, не используйте режим Mat и C .

  • Я не понимаю, что когда я рисую контуры с помощью cvDrawContours() , контуры полностью прорисовываются, но когда я лично перебираю точки контуров и рисую их поточно, кажется, что большинство из них не обнаружены!

Комментарии:

1. findContours имеет разные способы представления контура. Один из способов (по умолчанию) — сохранить только «некоторые» точки и выполнить интерполяцию между ними, предполагая прямые линии. Скорее всего, drawContours заполнит эти линии, но вы этого не делаете. В c для сохранения ВСЕХ точек используйте метод CV_CHAIN_APPROX_NONE . Согласно docs.opencv.org/modules/imgproc/doc/… Синтаксис C использует точно такой же параметр.

2. Я думал, что по умолчанию все точки сохранены. Спасибо

3. Почему вам, участникам stackoverflow, нравятся вопросы с необычными проблемами так, что вы с трудом понимаете их название? «Все простые вопросы будут отклонены» Я думаю, это должно быть вашим первым принципом в stackoverflow. Я искал, пытался часами и запутался! Так что это мое право спрашивать! Но вы думаете, что мой вопрос не является эпопеей в компьютерной индустрии, поэтому давайте сразу же снизим его!

Ответ №1:

Что касается вашего первого вопроса, в Интернете вы можете найти тысячи ссылок, объясняющих Erode, Dilate и все другие базовые принципы обработки изображений, не торопитесь с чтением документации, не перепрыгивайте через этапы .

Второй вопрос :

Я не уверен, чего вы ожидаете от центра контура? как вы думаете, у вас будет точка точно в центре этих эллипсов? НЕТ, этого никогда не произойдет, и если это так, поздравляю с этой большой кучей в истории обработки изображений!!

То, что я предлагаю сделать, — это простая манипуляция, которая решает вашу проблему :

  1. найдите контуры (точно так же, как вы делаете сейчас)
  2. вычислите центр каждого контура
  3. когда вы сравниваете ответы с расположением центров, не сравнивайте с использованием a == b , потому что этого никогда не происходит!! вместо этого используйте сравнение по расстоянию (пороговому значению), чтобы обеспечить работу вашего программного обеспечения

Пример :

 bool correct;
CvPoint answer, center;
double distance = sqrt((answer.X - center.X)^2   (answer.Y - center.Y)^2); // Euclidean distance

// judge using this distance 

if (distance <= 5)    // here you select the number as you (want) i gave example 5
{
    correct = true; // correct answer :)
}
  

Удачи

Комментарии:

1. Я не копировал следующие строки кода, в этих строках я точно сравниваю точки не с помощью ==, а сравнивая их с использованием диапазона «8 пикселей».

2. Спасибо, что сказали мне, что невозможно найти точный центр.