Мем

Prompt Engineer VS Sloperator meme

Что уже есть

Downscaled photo of puzzle example

Разбиваем на куски

Теперь благодаря морфологии с прошлого занятия мы получили чистую маску:

Good foreground mask after morphology

Как посчитать сколько у нас объектов? Как извлечь каждый объект чтобы работать с ним отдельно?

Objects with bboxes

Нам поможет Система Непересекающихся Множеств! (СНМ, Disjoint Set)

Подробнее можно почитать тут или послушать тут.

То есть хочется извлечь каждый объект - его картинку + его маску + его координаты в оригинальной картинке:

Extracted object with mask

В каждом куске находим границы

Подумайте, как можно найти координаты пикселей на периметре куска (причем упорядоченными - чтобы они сформировали цикл из пикселей):

Good foreground mask after morphology

Как решить эту задачу? В два шага:

1) Строим новую маску - множество пикселей лежащих на периметре (по простому критерию - среди 8 соседей должны быть и пиксели с фона, и пиксели объекта)

2) Эту новую маску обходим чем-то вроде поиска в ширину, но чтобы сохранять направление - выбираем среди соседей того что сохраняет моментум движения - то есть если предыдущий шаг был например направо, то и новый шаг должен быть как можно ближе к этому направлению

В каждом куске находим четыре стороны

А если у нас есть цикл из этих пикселей-вершин, то как разбить их на четыре множества - четыре стороны куска:

4 sides

Чего мы хотим

Взяв маску делящую картинку на объект и фон - вытащить отдельные объекты и каждый независимо обработать:

1) В каждом объекте выделить контур (периметр границы ввиде цепочки координат)

2) Через упрощение этого контура определить какие вершины были угловыми

3) Разбить контур на четыре части (четыре стороны объекта) по угловым вершинам

4) ???

5) Вы восхитительны - теперь вы знаете четыре цепочки пикселей являющихся стороной кусочка пазла

Практика

Задание 1.1 Обновите свой fork репозиторий, убедитесь что у вас все компилируется, запустите юнит-тесты All CTest:

Run All CTest

Задание 1.2 Заметьте что падает два набора юнит-тестов - те что проверяют функцию buildContourMask() и simplifyContour() - их вам нужно будет самостоятельно реализовать!

Задание 2.1 Запустите CVPuzzleSolver (выбрав сверху его вместо All CTest) - проверьте что результаты в debug вам нравятся и все хорошо работает. Программа будет падать с Error: Function buildContourMask() is not implemented! т.к. нужно будет реализовать две функции. Проверьте что построенный вами контур для каждого объекта выглядит хорошо.

Задание 2.2 У нас уже есть бинарная маска делящая фото на пиксели объекта и фона. Теперь нам нужно обработать каждый кусочек картинки. Для каждого кусочка постройте маску контура а затем и std::vector<point2i> - точки с контура. Проверьте через отладочные debug-визуализации. Теперь вам надо реализовать функцию занимающуюся упрощением геометрии. Проверьте что визуально она строит стороны правильно (цветная раскраска очень помогает):

buildContourMask()libs/images/libimages/algorithms/extract_contour.cpp) - реализуйте эту функцию, постройте маску пикселей лежащих на периметре

simplifyContour()libs/images/libimages/algorithms/simplify_contours.cpp) - реализуйте эту функцию, то есть удаляйте самые не-угловатые вершины из контура до тех пор пока не останется четыре угловые вершины

Задание 3 Ознакомьтесь с ускорением через OpenMP - запустите код и исследуйте - во сколько раз ускоряется морфология на вашем компьютере? Какое ускорение вы бы ожидали? Сколько ядер у вашего CPU? Какое ускорение вы пронаблюдали на практике? Попробуйте запустить несколько раз для надежности. Попробуйте ускорить обработку объектов - чтобы обработка одного объекта работала на отдельном ядре.

К следующему занятию

Задание 4 Подумайте, теперь мы знаем где границы каждого куска. Как теперь попробовать для каждой границы найти самую похожую на нее границу какого-то другого куска? Как измерить что такое “самая похожая”?