[Ненормальное программирование, Python, Программирование, Обработка изображений, Машинное обучение] Склеиваем несколько фотографий в одну длинную с помощью машинного обучения
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В предыдущих статьях был описан шеститочечный метод разворачивания этикеток и как мы тренировали нейронную сеть. В этой статье описано, как склеить фрагменты, сделанные из разных ракурсов, в одну длинную картинку.
Этикетки заранее сегментированы и развернуты нейронной сетью, описанной в предыдущей статье.
Как вообще работает склеивание? Нужно взять две картинки с нахлестом, посчитать взаимный сдвиг и наложить одну на другую. Звучит довольно просто, но давайте рассмотрим каждый из шагов.
Чтобы посчитать взаимный сдвиг, нужно найти какие-то объекты, которые присутствуют на обоих изображениях и вычислить каким-то образом преобразование точек с одной картинки на другую. Этот сдвиг может быть представлен матрицей преобразования, где элементы матрицы кодируют сразу несколько трансформаций — масштабирование, перенос и вращение.
Есть отличная таблица в википедии, где показано, как и какие элементы влияют на трансформацию:
https://en.wikipedia.org/wiki/Transformation_matrix#/media/File:2D_affine_transformation_matrix.svg
Как видно на картинке ниже, общих объектов вполне хватает:
Но выбранными объектами есть проблема — их сложно детектировать алгоритмически. Вместо этого, принято искать более простые объекты — так называемые “уголки” (“corners”), они же дескрипторы (“descriptors”, “features”).
Есть отличная статья в документации OpenCV, почему именно уголки — если вкратце, то определить линию легко, но она дает только одну координату. Поэтому нужно детектировать еще и вторую (не параллельную) линию. Если они сходятся в точке, то это место и есть идеальное для поиска дескриптора, он же является уголком (хотя реальные дескрипторы не являются уголками в геометрическом смысле этого слова).
Одним из алгоритмов по поиску дескрипторов, является SIFT (Scale-Invariant Feature Transform). Несмотря на то, что его изобрели в 1999, он довольно популярен из-за простоты и надежности. Этот алгоритм был запатентован, но патент истёк этой весной (2020). Тем не менее, его не успели перенести в основную сборку OpenCV, так что нужно использовать специальный non-free билд.
Так давайте же найдем похожие уголки на обоих изображениях:
sift = cv2.xfeatures2d.SIFT_create()
features_left = sift.detectAndCompute(left_image, None)
features_right = sift.detectAndCompute(left_image, None)
Воспользуемся составителем дескрипторов Фланна (Flann matcher) — у него хорошая производительность даже, если количество дескрипторов велико.
KNN = 2
LOWE = 0.7
TREES = 5
CHECKS = 50
matcher = cv2.FlannBasedMatcher({'algorithm': 0, 'trees': TREES}, {'checks': CHECKS})
matches = matcher.knnMatch(left_descriptors, right_descriptors, k=KNN)
logging.debug("filtering matches with lowe test")
positive = []
for left_match, right_match in matches:
if left_match.distance < LOWE * right_match.distance:
positive.append(left_match)
Желтые линии показывают, как сопоставитель нашёл совпадения.
Как хорошо видно — правильных совпадений примерно только половина. Однако, если правильные совпадения всегда дают одно и то же преобразование, то неправильные показывают хаотично новое направление. Т.е. теоретически, их можно как-то отделить друг от друга:
Одним из алгоритмов, чтобы найти правильное преобразование, является RANSAC. Этот алгоритм отлично работает, если нужно отделить хорошие значения от шумов — как раз наш случай.
К счастью, в OpenCV уже есть функции, которые найдут матрицу преобразования по совпадениям, используя RANSAC, т.е. фактически, ничего писать не придется.
Воспользуемся функцией estimateAffinePartial2D которая ищет следующие преобразования: поворот, масштабирование и перенос (4 степени свободы).
H, _ = cv2.estimateAffinePartial2D(right_matches, left_matches, False)
Когда матрица преобразования найдена, мы можем трансформировать правое изображение для склейки.
Левый фрагмент:
Правый фрагмент:
Для начала давайте воспользуемся простейшим способом склейки фрагментов, когда каждый пиксель их пересечения вычисляется, как среднее. К сожалению, результат получается так себе — изображение заметно двоится, особенно возле линии склейки.
На анимации различие между двумя кадрами видны более наглядно:
Это не удивительно — фотографии были сделаны под разными углами, нейронная сеть также развернула их слегка по-разному, и в итоге получились небольшие расхождения.
Для бесшовной склейки, необходимо компенсировать нелинейные искажения. Искажение можно представить в виде векторного поля того же разрешения, что и исходное изображение, только вместо цвета, в каждом пикселе будет закодирован сдвиг. Такое векторное поле называется “оптический поток”.
Вообще, есть разные методики вычисления оптического потока — некоторые из них встроены прямо в OpenCV, а есть и специальные нейронные сети.
В нашем же случае, конкретную методику я опущу, но опубликую результат:
Но компенсацию нужно осуществлять пропорционально обоих фрагментов. Для этого разделим его на две матрицы:
Левый фрагмент будет компенсироваться слева направо по нарастающей, в то время, как правый — наоборот.
Теперь оба фрагмента накладываются один на другой практически идеально:
Теперь наложение геометрически корректно, но мы наблюдаем весьма заметный скачок яркости на швах:
Эту проблему легко исправить, если вместо средних значений, накладывать их с градиентом:
С таким подходом, шва вообще не видно:
В принципе, есть еще и другие методики склейки, например, multiband blending, которые используют для склейки панорам, но они плохо работают с текстом — только компенсация оптического потока способно полностью убрать двоения на тексте.
Теперь склеиваем полное изображение:
Финальный варинат:
Дальнейшими улучшениями могут быть компенсация эффекта тени (правая сторона изображения), либо еще большая пост-обработка цвета и контрастности. Также видно, что слегка пострадала глобальная геометрия — линии справа чуть уползли вверх. Это проблему теоретически тоже можно исправить добавлением глобальной коррекцией масштабирования, но это тоже не совсем тривиальная задача.
Мы рассмотрели, как работает склейка, готовое решение доступно здесь в виде REST API, также рекомендую посмотреть следующие ссылки:
- SIFT explained docs.opencv.org/master/da/df5/tutorial_py_sift_intro.html
- OpenCV homography explained docs.opencv.org/master/d9/dab/tutorial_homography.html
- Panorama Autostitching matthewalunbrown.com/papers/ijcv2007.pdf
- OpenPano github.com/ppwwyyxx/OpenPano
- Google Photo Scanner ai.googleblog.com/2017/04/photoscan-taking-glare-free-pictures-of.html
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, IT-стандарты, Go] Let's Go! Три подхода к структурированию кода на Go (перевод)
- [Open source, Программирование, GitHub] Китай поставил задачу превратить Gitee в местный аналог GitHub
- [Программирование, TDD, Scala, ООП, Функциональное программирование] Изучаю Scala: Часть 3 — Юнит Тесты
- [Машинное обучение, Искусственный интеллект] Как машинное обучение и искусственный интеллект ускоряют поиск новых лекарств (перевод)
- [Python, Программирование, Изучение языков] Почему Python — плохой выбор для первого языка программирования?
- [Разработка под iOS, Разработка мобильных приложений, Обработка изображений] Обновление Lightroom для iPhone и iPad удалило фото пользователей. Некоторые из них уже не восстановить
- [Обработка изображений, Машинное обучение, Разработка под Arduino] Как с помощью HUAWEI ML Kit интегрировать в приложения стикеры с изображением лица
- [Программирование, Java] Что нового в Spring Data (Klara Dan von) Neumann (перевод)
- [Разработка веб-сайтов, Python, Управление разработкой] Исправь код, продай техническую фигню, покрути рулетку на Russian Python Week 2020
- [Тестирование IT-систем, Python, Тестирование мобильных приложений] Передача динамических объектов от setup к тестовой функции в py.test
Теги для поиска: #_nenormalnoe_programmirovanie (Ненормальное программирование), #_python, #_programmirovanie (Программирование), #_obrabotka_izobrazhenij (Обработка изображений), #_mashinnoe_obuchenie (Машинное обучение), #_python, #_opencv, #_numpy, #_sift, #_obrabotka_izobrazhenij (обработка изображений), #_nenormalnoe_programmirovanie (
Ненормальное программирование
), #_python, #_programmirovanie (
Программирование
), #_obrabotka_izobrazhenij (
Обработка изображений
), #_mashinnoe_obuchenie (
Машинное обучение
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:58
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В предыдущих статьях был описан шеститочечный метод разворачивания этикеток и как мы тренировали нейронную сеть. В этой статье описано, как склеить фрагменты, сделанные из разных ракурсов, в одну длинную картинку. Этикетки заранее сегментированы и развернуты нейронной сетью, описанной в предыдущей статье. Как вообще работает склеивание? Нужно взять две картинки с нахлестом, посчитать взаимный сдвиг и наложить одну на другую. Звучит довольно просто, но давайте рассмотрим каждый из шагов. Чтобы посчитать взаимный сдвиг, нужно найти какие-то объекты, которые присутствуют на обоих изображениях и вычислить каким-то образом преобразование точек с одной картинки на другую. Этот сдвиг может быть представлен матрицей преобразования, где элементы матрицы кодируют сразу несколько трансформаций — масштабирование, перенос и вращение. Есть отличная таблица в википедии, где показано, как и какие элементы влияют на трансформацию: https://en.wikipedia.org/wiki/Transformation_matrix#/media/File:2D_affine_transformation_matrix.svg Как видно на картинке ниже, общих объектов вполне хватает: Но выбранными объектами есть проблема — их сложно детектировать алгоритмически. Вместо этого, принято искать более простые объекты — так называемые “уголки” (“corners”), они же дескрипторы (“descriptors”, “features”). Есть отличная статья в документации OpenCV, почему именно уголки — если вкратце, то определить линию легко, но она дает только одну координату. Поэтому нужно детектировать еще и вторую (не параллельную) линию. Если они сходятся в точке, то это место и есть идеальное для поиска дескриптора, он же является уголком (хотя реальные дескрипторы не являются уголками в геометрическом смысле этого слова). Одним из алгоритмов по поиску дескрипторов, является SIFT (Scale-Invariant Feature Transform). Несмотря на то, что его изобрели в 1999, он довольно популярен из-за простоты и надежности. Этот алгоритм был запатентован, но патент истёк этой весной (2020). Тем не менее, его не успели перенести в основную сборку OpenCV, так что нужно использовать специальный non-free билд. Так давайте же найдем похожие уголки на обоих изображениях: sift = cv2.xfeatures2d.SIFT_create()
features_left = sift.detectAndCompute(left_image, None) features_right = sift.detectAndCompute(left_image, None)
Воспользуемся составителем дескрипторов Фланна (Flann matcher) — у него хорошая производительность даже, если количество дескрипторов велико. KNN = 2
LOWE = 0.7 TREES = 5 CHECKS = 50 matcher = cv2.FlannBasedMatcher({'algorithm': 0, 'trees': TREES}, {'checks': CHECKS}) matches = matcher.knnMatch(left_descriptors, right_descriptors, k=KNN) logging.debug("filtering matches with lowe test") positive = [] for left_match, right_match in matches: if left_match.distance < LOWE * right_match.distance: positive.append(left_match) Желтые линии показывают, как сопоставитель нашёл совпадения. Как хорошо видно — правильных совпадений примерно только половина. Однако, если правильные совпадения всегда дают одно и то же преобразование, то неправильные показывают хаотично новое направление. Т.е. теоретически, их можно как-то отделить друг от друга: Одним из алгоритмов, чтобы найти правильное преобразование, является RANSAC. Этот алгоритм отлично работает, если нужно отделить хорошие значения от шумов — как раз наш случай. К счастью, в OpenCV уже есть функции, которые найдут матрицу преобразования по совпадениям, используя RANSAC, т.е. фактически, ничего писать не придется. Воспользуемся функцией estimateAffinePartial2D которая ищет следующие преобразования: поворот, масштабирование и перенос (4 степени свободы). H, _ = cv2.estimateAffinePartial2D(right_matches, left_matches, False)
Когда матрица преобразования найдена, мы можем трансформировать правое изображение для склейки. Левый фрагмент: Правый фрагмент: Для начала давайте воспользуемся простейшим способом склейки фрагментов, когда каждый пиксель их пересечения вычисляется, как среднее. К сожалению, результат получается так себе — изображение заметно двоится, особенно возле линии склейки. На анимации различие между двумя кадрами видны более наглядно: Это не удивительно — фотографии были сделаны под разными углами, нейронная сеть также развернула их слегка по-разному, и в итоге получились небольшие расхождения. Для бесшовной склейки, необходимо компенсировать нелинейные искажения. Искажение можно представить в виде векторного поля того же разрешения, что и исходное изображение, только вместо цвета, в каждом пикселе будет закодирован сдвиг. Такое векторное поле называется “оптический поток”. Вообще, есть разные методики вычисления оптического потока — некоторые из них встроены прямо в OpenCV, а есть и специальные нейронные сети. В нашем же случае, конкретную методику я опущу, но опубликую результат: Но компенсацию нужно осуществлять пропорционально обоих фрагментов. Для этого разделим его на две матрицы: Левый фрагмент будет компенсироваться слева направо по нарастающей, в то время, как правый — наоборот. Теперь оба фрагмента накладываются один на другой практически идеально: Теперь наложение геометрически корректно, но мы наблюдаем весьма заметный скачок яркости на швах: Эту проблему легко исправить, если вместо средних значений, накладывать их с градиентом: С таким подходом, шва вообще не видно: В принципе, есть еще и другие методики склейки, например, multiband blending, которые используют для склейки панорам, но они плохо работают с текстом — только компенсация оптического потока способно полностью убрать двоения на тексте. Теперь склеиваем полное изображение: Финальный варинат: Дальнейшими улучшениями могут быть компенсация эффекта тени (правая сторона изображения), либо еще большая пост-обработка цвета и контрастности. Также видно, что слегка пострадала глобальная геометрия — линии справа чуть уползли вверх. Это проблему теоретически тоже можно исправить добавлением глобальной коррекцией масштабирования, но это тоже не совсем тривиальная задача. Мы рассмотрели, как работает склейка, готовое решение доступно здесь в виде REST API, также рекомендую посмотреть следующие ссылки:
=========== Источник: habr.com =========== Похожие новости:
Ненормальное программирование ), #_python, #_programmirovanie ( Программирование ), #_obrabotka_izobrazhenij ( Обработка изображений ), #_mashinnoe_obuchenie ( Машинное обучение ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:58
Часовой пояс: UTC + 5