Как обнаружить паттерн с несколькими барами?

Я хочу обнаружить на изображении пользовательский "шаблон из нескольких полос".

Паттерн выглядит так: группа параллельных черных полос одинаковой ширины, но разной высоты, см. это изображение:

изображение 1

Этот шаблон может быть на изображении или даже не быть, но если он есть, я хотел бы получить его позицию.

Примечание. Цвет рисунка всегда черный.

Примечание. Размер шаблона неизвестен, поэтому он может быть большим или очень маленьким.

Примечание. Количество полос шаблона является фиксированным числом. Оно будет одинаковым (в данном случае 7) для каждого случая.


Изображение может выглядеть так:

Изображение

И после выполнения алгоритма поиска кода должно получиться вот это:

введите здесь описание изображения


Любая помощь будет очень признательна. Заранее огромное спасибо, Темпи.

Примечание. Код, который я получил на данный момент, (не работает)

Mat myImage; // this is the mat of the photo you can see above
Mat algorithmImage;
myImage.coptyTo(algorithmImage); 
cvtColor(algorithmImage, algorithmImage, CV_RGB2HSV);

double imgThreshold = 20;
cv::inRange(algorithmImage, cv::Scalar(0, 0, 0, 0), cv::Scalar(180, 255, 30, 0), 20);

Mat canny;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;

Canny( algorithmImage, canny, 3, 6, 3 );
findContours( canny, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

for( int i = 0; i<contours.size(); i++ ) {
  // ??
}

bool isLineAlreadyFound(const Vec4i& _l1, const Vec4i& _l2) {
    Vec4i l1(_l1), l2(_l2);

    float length1 = sqrtf((l1[2] - l1[0])*(l1[2] - l1[0]) + (l1[3] - l1[1])*(l1[3] - l1[1]));
    float length2 = sqrtf((l2[2] - l2[0])*(l2[2] - l2[0]) + (l2[3] - l2[1])*(l2[3] - l2[1]));

    float product = (l1[2] - l1[0])*(l2[2] - l2[0]) + (l1[3] - l1[1])*(l2[3] - l2[1]);

    if (fabs(product / (length1 * length2)) < cos(CV_PI / 30))
        return false;

    float mx1 = (l1[0] + l1[2]) * 0.5f;
    float mx2 = (l2[0] + l2[2]) * 0.5f;

    float my1 = (l1[1] + l1[3]) * 0.5f;
    float my2 = (l2[1] + l2[3]) * 0.5f;
    float dist = sqrtf((mx1 - mx2)*(mx1 - mx2) + (my1 - my2)*(my1 - my2));

    if (dist > std::max(length1, length2) * 0.5f)
        return false;

    return true;
}

person Community    schedule 04.04.2018    source источник
comment
Произвольный размер и вращение делают эту проблему сложной. Есть ли определенный набор поворотов, например, кратный 45 градусам?   -  person stark    schedule 04.04.2018
comment
@stark: Вовсе нет. Это, конечно, не проблема C++. В распознавании образов это тривиально.   -  person MSalters    schedule 05.04.2018
comment
Тривиально? Тем не менее, 3 радикально разных ответа. Ни один из них не предлагает, как определить, что является верхом или низом результирующего шаблона.   -  person stark    schedule 06.04.2018


Ответы (2)


Вот как бы я подошел к вашей проблеме.

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

  • После вышеописанного шага использование findContours уже должно хорошо справляться с обнаружением фигур. Но вам понадобится способ распознать свой шаблон. Поскольку ваши шаблоны могут отображаться в другом масштабе и/или ориентации, вам понадобится инвариантный дескриптор масштаба/ориентации. Я имею в виду здесь, дескриптор формы. Моменты Ху можно посмотреть на https://en.wikipedia.org/wiki/Image_moment. .

  • Это будет только для одного бара в каждом паттерне. Вы должны завершить поиск, разработав конкретную функцию для своего шаблона с помощью функций, извлеченных из каждого бара.

person Soheyb Kadi    schedule 05.04.2018

Хитрость здесь в том, что у вас есть 14 параллельных ребер. Их невозможно пропустить. Как отмечено в другом ответе, порог для их изоляции. Сразу после этого запустите детектор границ. Это превращает черно-белые края в линии, в то время как остальная часть изображения может создавать несколько разбросанных пикселей. Визуализируйте это, чтобы убедиться в этом.

Затем запустите преобразование Хафа из OpenCV. Это дает вам линии в формате {смещение, направление}. Даже если несколько разбросанных фоновых пикселей случайно выровняются, они не образуют 14 линий с одинаковым направлением.

Вы можете рассчитать максимальную разницу смещений, чтобы найти масштаб штрихового рисунка, и перепроверить относительные смещения, чтобы проверить ширину и интервалы отдельных штрихов. Помните, что 14 линий — это ребра, поэтому вам нужно соединить их.

К этому моменту вы определили направление и масштаб барного паттерна. может быть немного удивительно осознавать, что вы на самом деле не идентифицировали фактическое положение бара. Причина этой процедуры в том, что мы сначала решаем сложную проблему. Теперь вернемся к результату обнаружения краев и разделим все края на три категории: параллельные края, закругленные концы между двумя парами параллельных краев (следуя контурам) и случайные фоновые пиксели. Вам может понадобиться операция MORPH_CLOSE, чтобы закрыть промежутки в контуре.

person MSalters    schedule 05.04.2018