Распознавание объектов в изображениях с помощью каскада HAAR и OpenCV

(Это вышло немного долго, но это в основном трудно понять объяснение :)

для проекта мне нужно распознать объекты, которые в общем виде выглядят так -

Object to be recognised

внутри большего изображения, которое содержит различные формы, как этот - container image

как вы можете видеть, объект, который я ищу, - это красная линия с крестами с каждой стороны (на последнем снимке их 5). У меня есть банк вокруг 4000 изображений, в которых мне нужно найти объект, некоторые из них содержат эти объекты, а некоторые нет, как это изображение - An image without the desired object

после проведения некоторых исследований я понял, что использование каскадов haar и openCV-это путь, поэтому я написал сценарий, который проходит через все вышеупомянутые изображения 4,000 и извлекает отдельные контуры, как первое изображение в этом вопросе.

затем я прошел через множество контуров, схватил около 150 из них (то есть 150 файлов которые содержат только нужный мне объект, похожий на первое изображение) и около 180 изображений, которые не содержат нужного мне объекта (аналогично третьему изображению здесь).

затем я начал учебный процесс, используя несколько учебных пособий, но в основном этот.

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

сначала я попытался использовать изображения с другим измерением, но это вызвало ошибки в процессе обучения, поэтому, чтобы обойти это, я изменил размер всех положительных изображений на 350x350 (самый большой масштаб одного из объектов). Просто чтобы быть ясным - я не изменял размер изображений - я просто добавил пробел, чтобы все изображения были 350x350 пикселей.

затем я прошел через учебный процесс, как было предложено в учебнике-я создал образцы (ширина-24, высота-24) и создал каскадный xml-файл, который оказался не очень большим (45кб).

Теперь я знаю, что 150 положительных изображений и 180 отрицательных-это не так много, но я хотел, по крайней мере, получить доказательство концепции, прежде чем фильтровать больше изображений и вкладывать в него больше времени.

когда каскад.XML-файл был сделан, я попытался использовать его, чтобы найти некоторые объекты в некоторых изображений (используя cv2.CascadeClassifier('cascade.xml') и cascade.detectMultiScale(img) но каждая попытка результат нулевой.

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

Я попытался настроить параметры cascade.detectMultiScale(img) и в настоящее время я тренирую каскадный файл с образцами 36x36, но я не уверен, что он будет работать.

Так как я довольно новичок в этом материале, мне было интересно, что я делаю неправильно, и я подумал, что спрошу здесь.

более конкретно:

  • считаете ли вы, что использование haar правильно в этом контексте? Должен ли я использовать другой метод распознавания объектов?
  • могут ли положительные размеры изображений быть источником проблемы? Если да, то как я могу это сделать?

Если я не включил некоторые важные данные, пожалуйста, дайте мне знать и я выложу его.

большое спасибо за вашу помощь, Дэн!--4-->

1 ответов


Я думаю, вы не получите хороших результатов от каскадных классификаторов haar (или hog) здесь.

  • ваша "игла" не имеет достаточного количества функций / углов (это всего лишь 2 креста и линия)
  • каскадные классификаторы довольно чувствительны к вращению. кажется, ваш объект может принимать любое произвольное вращение здесь.
  • если вы тренируете классификатор со многими различными вращениями, он будет просто overfit.
  • если вы тренируетесь много классификаторы(по одному на ротация), - то же самое. ;(

Итак, имхо, не много надежды на такой подход.

Я бы пошел для контуров/shapeMatching вместо этого:

void findNeedles( const std::vector<cv::Point> & needle_contour, const cv::Mat & haystack_binarized)
{
    int nfound = 0;
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(haystack_binarized, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
    for (size_t i = 0; i < contours.size(); i++)
    {
        // pre-filter for size:
        if ( ( contours[i].size() < needle_contour.size()/2 )
          || ( contours[i].size() > needle_contour.size()*2 ) )
          continue;

        double d = cv::matchShapes(contours[i],needle_contour,CV_CONTOURS_MATCH_I2,0);
        if ( d < 8.4 ) // heuristic value, experiments needed !!
        {
            cv::drawContours(haystack_binarized, contours, i, 128, 3);
            nfound ++;
        }
    }
    cerr << nfound << " objects found" << endl;
    cv::imshow("haystack",haystack_binarized);
    //imwrite("hay.png",haystack_binarized);
    cv::waitKey();
}


int main()
{
    // 1. get the contour of our needle:
    Mat needle = imread("needle.png",0);
    Mat needle_b; 
    threshold(needle,needle_b,120,255,1); 
    imshow("needle",needle_b);

    std::vector<std::vector<cv::Point>> needle_conts;
    cv::findContours(needle_b, needle_conts, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
    if ( needle_conts.size() == 0 )
    {
        std::cout << " no contour Found" << std::endl;
        return -1;
    }
    std::vector<cv::Point> needle_contour = needle_conts[0];

    // 2. check a positive sample:
    Mat haypos = imread("hay_pos.png",0);
    Mat haypos_b; 
    threshold(haypos,haypos_b,120,255,1);
    findNeedles(needle_contour, haypos_b);

    // 3. check a negative sample:
    Mat hayneg = imread("hay_neg.png",0);
    Mat hayneg_b; 
    threshold(hayneg,hayneg_b,120,255,1);
    findNeedles(needle_contour, hayneg_b);

    return 0;
}

--------------

> haystack.exe
5 objects found
0 objects found

enter image description here