Занятие 7: Сшиваем пазл в единую картинку
Мем

Используйте Extended Thinking/DeepThink у LLM
Очень советую для средних и сложных задач использовать “сильно старайся” режим:

И в целом попробуйте какую-нибудь среднюю по сложности задачку обработать с и без этих галок, посмотрите на разницу в качестве.
Попробуйте обработать в разных LLM которые вам доступны.
Не стоит каждый день тратить время на такие эксперименты, но изредка пробовать, или хотя бы один раз выяснить где ваши задачи решаются лушче-хуже - стоит того.
Описание преобразования системы координат через матрицы

План решения
Есть исходная картинка:
![]() |
В ней нашли куски-объекты, в каждом из них нашли стороны:

Для каждой стороны (кроме тех что являются белыми) нашли самую похожую сторону:

Теперь хотим объединить все это в прямоугольник, например такой:

План
Итак у нас есть:
1) objOffsets, objImages, objMasks - извлеченные изображения объектов-кусочков (с маской и смещением указывающим на позицию в целой картинке)
2) objSides[obj][side] - vector<point2i> - координаты пикселей стороны side объекта obj (в его извлеченном изображении)
3) objMatchedSides[objA][sideA] = {objB, sideB, ...}; - информация о том с каким (objB, sideB) нас сопоставило, или (-1, -1) если мы являемся белым краем
План:
1) Построить граф: вершины - объекты, ребра - сопоставления с другими объектами (из objMatchedSides)
2) Найти в графе вершины-углы - попробовать выложить паззл начиная с них
3) Найдя угол выясним сколько кусочков в ширину - прошагаем по графу вправо до упора
4) Так же выясним сколько кусочков в высоту - шагаем от угла вниз до упора
5) Сверяем что ширина * высоту = числу кусочков (иначе - пропускаем этот уголок, попробуем начать с другого)
6) Создаем двумерный массив, каждая ячейка будет хранить номер кусочка-объекта + число поворотов по часовой стрелке (такое чтобы side0 смотрело направо, соответственно side1 - вниз, и т.д.)
7) Выводим его для проверки в консоль
8) Заполняем его распространяясь в ширину от кусочка-уголка
9) Задание 1 Определим ширину/высоту каждого столбика/строки пазла (медиана от ширин/высот назначенных кусочков)
10) Найдем для каждого кусочка матрицу описывающую переход из его изображения в общий холст
11) Спроецируем все кусочки этой матрицей
Используйте схему: планируем + потом пишем код
Это полезно и для LLM, и когда вы кодите самостоятельно!
Разбейте задачу на кусочки, затем сформулируйте максимально подробно каждый этап, пояснив что под каким термином вы подразумеваете.
И если задача сложная - лучше даже попросить нейросеть прежде чем писать код - пусть расскажет какой у нее план по реализации каждого этапа.
Ознакомьтесь с планом, часто по нему можно понять что она не правильно поняла вашу задумку - внесите коррективы, ответьте на ее уточняющие вопросы.
Пример промпта:
выполни TODO План в коде приложенном ниже
прежде чем писать код - задай уточняющие вопросы если они есть
и в целом расскажи мне про каждый шаг как примерно будешь реализовывать
если планируешь создать какие-то отдельные новые исходники - так же скажи мне об этом
после этого обсуждения я скажу тебе начать писать код
main.cpp:
...
ПОЛНЫЙ КОД
...
// Занятие 7
// Итак у нас есть:
// 1) objOffsets, objImages, objMasks - извлеченные изображения объектов-кусочков (с маской и смещением указывающим на позицию в целой картинке)
// 2) objSides[obj][side] - vector<point2i> - координаты пикселей стороны side объекта obj (в его извлеченном изображении)
// 3) objMatchedSides[objA][sideA] = {objB, sideB, ...}; - информация о том с каким (objB, sideB) нас сопоставило, или (-1, -1) если мы являемся белым краем
// TODO План:
// 1) Построить граф: вершины - объекты, ребра - сопоставления с другими объектами (из objMatchedSides)
// 2) Найти в графе вершины-углы - попробовать выложить паззл начиная с них
// 3) Найдя угол выясним сколько кусочков в ширину - прошагаем по графу вправо до упора
// 4) Так же выясним сколько кусочков в высоту - шагаем от угла вниз до упора
// 5) Сверяем что ширина * высоту = числу кусочков (иначе - пропускаем этот уголок, попробуем начать с другого)
// 6) Создаем двумерный массив, каждая ячейка будет хранить номер кусочка-объекта + число поворотов по часовой стрелке (такое чтобы side0 смотрело направо, соответственно side1 - вниз, и т.д.) - TODO
// 7) Выводим его для проверки в консоль
// 8) Заполняем его распространяясь в ширину от кусочка-уголка
// 9) Определим ширину/высоту каждого столбика/строки пазла (медиана от ширин/высот назначенных кусочков) - TODO (пока что захардкодить константный размер)
// 10) Найдем для каждого кусочка матрицу описывающую переход из его изображения в общий холст
// 11) Спроецируем все кусочки этой матрицей
...
ОСТАЛЬНОЙ КОД
...
Практика
Пред-задание Обновите свой fork репозиторий, убедитесь что у вас все компилируется, запустите юнит-тесты All CTest:

UPD: так как теперь в репозитории выложены все задания, то вам нужно не обновить до самой свежей версии - а скачать версию актуальную для этого занятия 7. Поэтому скачайте исходники по этой ссылке (и там Source code (zip)).
Пред-задание Запустите CVPuzzleSolver (выбрав сверху его вместо All CTest) - проверьте что результаты в debug вам нравятся и все хорошо работает. Что строятся графики сопоставляемых сторон.
Задание 1 Найдите в коде (поиском по папке src) TODO комментарий, сейчас все строчки и столбцы - 200 пикселей, оцените вместо этого их медианой по кусочкам паззла.
Задание 2 Попробуйте запуститься на других фотографиях - работает ли? Попробуйте понять через визуализации - почему так? Попробуйте улучшить алгоритм. Если все фотографии заработают - здорово! Позовите меня пожалуйста!
Что еще можно было бы добавить
Можно было бы попробовать поддержать настоящие паззлы:

Упражнение Подумайте, применим ли наш метод сейчас если бы на черном фоне лежали кусочки обычного паззла? Сработает ли наш алгоритм?
Упражнение Подумайте, как можно сделать стыковку швов результата более четкой? Как склеить идеально?
Упражнение Подумайте, а если граф найденных сопоставлений не полон, например есть противоречивые не симметричные ребра - можем ли мы в каких-то случаях все-равно найти правильный ответ?
Курсы в CS Space: видеокарты и фотограмметрия
Если вас в целом зацепило то что мы делали в рамках мини-курса, то может быть вам позже (вероятно через несколько лет, скорее курсе на втором-третьем-четвертом) может быть интересно:

