> For the complete documentation index, see [llms.txt](https://lahmeneffaa.gitbook.io/nto.game.vr/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lahmeneffaa.gitbook.io/nto.game.vr/ar/modul-2.-teoreticheskie-osnovy-dopolnennoi-realnosti/deskriptory-i-klyuchevye-tochki.md).

# Дескрипторы и ключевые точки

**Ключевые слова:** *Target, opencv, matplotlib, numpy, BFMatcher, queryIdx, trainIdx, distance, img2kp,&#x20;*&#x20;*similarity*<br>

Библиотеки, которые понадобятся в процессе данного урока: это numpy, opencv и библиотека для визуализации изображения и графиков — matplotlib.&#x20;

![](https://sun9-27.userapi.com/s/v1/if2/IK564qr6wmX3SA4TX3tbwkJKQOPDKuXEPQmaRYhJNwbFwUhNJO_0_HJbvSY_w-hepPf3CcQpuIOH2h5xADDF7gfD.jpg?size=492x129\&quality=96\&type=album)<br>

В первую очередь загружаем картинку. Задача: реализовать такой программный код, который по видео потоку или по фотографии этого изображения, будет находить таргет на снимке.&#x20;

![](https://sun9-78.userapi.com/s/v1/if2/-EJw3-sP_TGqPTTTlcYGPfOVq6NvwQ1MBalPYcX6q8DnczNLLEYpfsttQiutUPFDH3h7QEpPqk5sQ31iMnbhP65w.jpg?size=689x619\&quality=96\&type=album)<br>

**Orb** — новый метод. В данной строчке инициализируем сам алгоритм, а параметр, который передается, это количество особенностей, которые есть в таргете и которые нужно выделить из изображения.

![](https://sun9-49.userapi.com/s/v1/if2/TjbxRz4RKEQ8WtagQac9FZr1oR9Vf9pY4fGDcW2ak_UCbBFpPyJ481DDtONGNIQvJWHn8t9Re_dxh5ff5l8PINH2.jpg?size=531x52\&quality=96\&type=album)<br>

Следующая строчка позволяет выделить ключевые точки и дескрипторы.

![](https://sun9-27.userapi.com/s/v1/if2/m1zC74ItK642amUeRJxNbT1aavLooHsy_yoCtwB1Im2u9HY_rqczlQ30Y2p-05b2JV9wSSMm3oXhkXDKAjYqvwCm.jpg?size=662x54\&quality=96\&type=album)<br>

Реализуем функцию, которая рисует ключевые точки поверх изображения. На вход этой функции передается изображение и ключевые точки. Первая строчка позволяет из объекта *key points* выделять координаты ключевых точек, а следующие строчки отвечают за отрисовку.

![](https://sun4-11.userapi.com/s/v1/if2/0MlP-W9LdiU1ZKXXxPGxSSi2K3xK4CUU9Tti3mgNmNcFJhGXEvyNwrnpfHqgYNd41THs-cJEx0bvHYKrHwXc-3jT.jpg?size=1280x180\&quality=96\&type=album)<br>

Синие круги на картинке, это те особенности, которые характеризуют изображение, т. е ключевые точки, которые в дальнейшем ищутся на снимках или в видеопотоке.&#x20;

![](https://sun9-24.userapi.com/s/v1/if2/xvCJKdpFZYR_C2wvucDHOEj5bAIw021_HcyxWne3R3hZ1HlQtA8RAen26oBQ7YK_QogrNOGk2juze9xBe_xtFrP-.jpg?size=1091x1003\&quality=96\&type=album)<br>

Загрузим снимок с данной картинкой, для того, чтобы начать искать ее на изображении.

![](https://sun9-32.userapi.com/s/v1/if2/EsqVdPQ9-Vn_-ro70ZA2uEUA571EwUbuDK26IMVDDnUef5z2nHfXwHth5bNV25636WZfwn5_HuA3ly4ZTrz6oWVA.jpg?size=486x56\&quality=96\&type=album)\
Выделим ключевые точки и отрисуем их поверх рисунка.

![](https://sun9-35.userapi.com/s/v1/if2/r6syXD53hb1IbNEfP63hSggZvYiAAkc4kIL8TeWCCoUOUodBUHDSz3dvG1uTp2bVfYt5n6ESj3XO_23crUTva2td.jpg?size=1114x968\&quality=96\&type=album)<br>

Нужно сопоставить те ключевые точки, которые есть на таргете и ключевые точки, которые были найдены на снимке. Для этого будем использовать специальный алгоритм BFMatcher. Он сопоставляет по описанию дескрипторов наилучшую подходящую точку.&#x20;

![](https://sun4-15.userapi.com/s/v1/if2/AJvGP-GZYwrfMD0Hk0_bfBlg1gU6tXetlOEN6I3c2fJDeBW13akHc3QN8Ct8vZ6vtN6jFwqEVWhcOz2L9FZf3oU2.jpg?size=771x83\&quality=96\&type=album)<br>

Посмотрим подробнее на то, что хранится в объекте **matches.** Параметры, которые есть в совпадениях, это параметр **distance.** Это расстояние, от каждой точки до точки, с которой ее сопоставили. **imgIdx** — это индекс изображения, однако данный параметр не пригодится. **queryIdx** и **trainIdx** будут рассмотрены в конце лекции.

![](https://sun9-78.userapi.com/s/v1/if2/hBR2GS7EcFRZl2zsn4Ft5MkF51wJNzWUeZPq4PPdRelb7FTOKQXZvQsg_FmSkYm9eLR0CIAAQdCblsTqCMjMF2BC.jpg?size=1097x1097\&quality=96\&type=album)<br>

Сопоставим ключевые точки таргета и ключевые точки со снимка. Для этого используем специальный алгоритм, который уже есть в **opencv** — *drawMatches*. Внутрь него передадим изображение, ключевые точки с таргета, фото, снимок, сделанный с таргетом, ключевые точки, которые есть на таргете и так же объект matches. Передаем в него только 10 сопоставлений и, соответственно, отрисовываться тоже будет всего 10 точек.&#x20;

![](https://sun9-11.userapi.com/s/v1/if2/FImUGhBwjzOhl01QcXR8ZCjvgsFTqisbqykEhKTBg624T13hGxbdFkedGdcy-TR-h3UHuf0AL10EHEs47BVUV4Zj.jpg?size=1280x668\&quality=96\&type=album)<br>

Теперь необходимо написать некоторый алгоритм, который бы позволил распознавать несколько изображений. Так, как это обычно делается в библиотеке *Vuforia*. Несколько изображений загружаются в базу и приложение распознает любое из этих изображений.

Реализуем класс, который будет называться ***ImageBase*****.** Какие методы будут у данного класса? Метод инициализации, в котором инициализируем алгоритм *orb* и алгоритм ***bf*** для сопоставления изображений в базе и снимков.&#x20;

Реализуем метод ***load\_base***, который будет загружать изображение из определенной папки и выделять на этих изображениях ключевые точки и дескрипторы.&#x20;

Также необходим метод ***img2kp,*** в этот метод передается изображение, а он возвращает ключевые точки и дескрипторы.

Реализуем метод ***similarity***, который будет вычислять сходность дескрипторов с одного изображения и дескрипторов со второго изображения. На выходе он будет возвращать расстояние между двумя дескрипторами и также объект *matches.*&#x20;

![](https://sun9-78.userapi.com/s/v1/if2/O12jvViNyUUKe1wyJBCxmy0UWHxbCfbxLpN3455i2ddel4tJjtIx31NDnLp-YiIkcXEsqbVbxgELt4CE8PR3m4Uj.jpg?size=940x787\&quality=96\&type=album)<br>

Далее реализуем метод ***find\_similar.*** Он будет искать по всей базе наиболее подходящий таргет к нашему снимку.&#x20;

И дополнительно, на всякий случай, реализуем метод ***find\_similar\_desc.*** Который будет искать наилучшие совпадение, но только по ключевым точкам.&#x20;

![](https://sun9-64.userapi.com/s/v1/if2/e9dW1R57LLjpzDNBorwogepZT73aP8iCb5o9LPYmid8PM6puuOxpurFUns4HL4lzr16whMOCC07M6AlHMmTzwiTb.jpg?size=754x527\&quality=96\&type=album)<br>

Давайте посмотрим какие изображения есть базе. Все 10 картинок имеют множество деталей, поэтому они будут хорошо работать для данного алгоритма. Загрузим изображения.&#x20;

![](https://sun4-12.userapi.com/s/v1/if2/INMXkbZpvX_KftMuGButTYCqLZtEKrw21ihqrxPBHuH8gheVzi8yzMHnskubuFeg7xGQh-Q8RaYOKcWI8XZRWNZ0.jpg?size=538x113\&quality=96\&type=album)<br>

В объекте *img\_paths* хранится путь к каждой картинке.

![](https://sun9-44.userapi.com/s/v1/if2/e2qMjDg7ua9B-5SAZEclu4whUX6q7eq9xiN8ow_0-g_WkvZXPhYs59pjVEktzFBaESO56rVE8sL8ACT5IK9VCfEw.jpg?size=408x390\&quality=96\&type=album)<br>

Теперь загрузим все изображения и инициализируем нашу базу. Передадим в ***load\_base*** картинки, которые уже были загружены ранее.

![](https://sun4-10.userapi.com/s/v1/if2/3W9XmCv3xJjrX-_DhdsLS8GeNfjRbJlSg7s77zfqUVKMIf95wvtXEWYfqj3t1_eD6qFn3bc0oE_WmmZYdW1_9fmC.jpg?size=413x362\&quality=96\&type=album)<br>

Для того, чтобы проверить, что у нас все работает, попробуем сделать следующее. Передадим в нашу базу для поиска схожего изображения, одну из картинок из этой же базы.&#x20;

Визуализируем картинку.

![](https://sun9-82.userapi.com/s/v1/if2/altJCRgGz6fy8mz8SVv9moC9zIrG7Sb0cNF_yayxzbZ9TxNRf1OL5dKniffBUr8zlZs3A2ChxEtKzTvDp-YmIYUW.jpg?size=767x707\&quality=96\&type=album)

Попробуем найти таргет для этого снимка.

![](https://sun9-82.userapi.com/s/v1/if2/_7h8ba3b7dcvTNueAfMfF7QAa6GO-wda4eSyBi4urM7wa_9Jq04mMpeXEBdBROGZmvK4ZjZASswitjOxCLVy72di.jpg?size=646x1080\&quality=96\&type=album)\ <br>

Исходный таргет был найден, сопоставлен снимок и изображение из базы. Но, к сожалению, в жизни все не так хорошо и не всегда удается сопоставить наш снимок с изображением.&#x20;

**Что влияет на качество распознавания?**<br>

К сожалению, данный алгоритм очень чувствителен к масштабу. Допустим, если изображение снимается телефоном, как чаще всего бывают в дополненной реальности, размер снимка гораздо меньше чем размер таргета в базе.&#x20;

![](https://sun4-17.userapi.com/s/v1/if2/v8vRyyPEa2pm5kyZ7VolpfWciO_1MALzLXTa_g2bPRit-iZfsWJMiXtnIqq7LwLzUYskzY3JCLiKxylA8XM0U1xq.jpg?size=649x1080\&quality=96\&type=album)<br>

Можно попробовать передавать не все ключевые точки, а передавать только первые 50. Это очень важный момент, иногда такой подход может срабатывать, потому что при инициализации объекта ***matches,*** ключевые точки в нем отсортированы по наименьшей дистанции. Самые первые ключевые точки, это те ключевые точки, которые наилучшим образом описывает наш объект. Однако снова возвращается не тот объект, который мы ждем.&#x20;

![](https://sun4-17.userapi.com/s/v1/if2/Ju2jCJSUd-qiqkjlfzDHAjDAfxrAO7RxiyhZhdtOaA40ChwUgA9bbYJrlS205ZAhHbrV2LGjJNwyjM8d82psMdcA.jpg?size=630x573\&quality=96\&type=album)<br>

Давайте приведем изображение в базе и изображение, которое передается, к одному масштабу. Для этого напишем специальную функцию ***zip\_img.*** Она принимает изображение, некоторый параметр, к примерному размеру которого нужно свести наше оригинальное изображение и реальный размер картинки. Функция старается привести изображение в ***real\_size*** (таргет) к тому размеру, который есть в базе.

![](https://sun4-17.userapi.com/s/v1/if2/g4frX6O2QXqQ7q-SX3wa6GqyWtIhC5NsxckbFkIdHvx5bn0yEFg_a1KQ9SW0WSbtcarWC40VazR8OV0Z2mRgAvm-.jpg?size=816x366\&quality=96\&type=album)<br>

Давайте рассмотрим как данный алгоритм будет работать сначала на таргете, а потом на снимке. Видим, что таргет приведен к размеру 400х400. На вход передаем изображения, примерный размер и исходный размер нашего таргета.&#x20;

![](https://sun9-4.userapi.com/s/v1/if2/ff_DJKXMCZXCTY05Yz1kN8sg62TxT4YwEQM-J2ni4dSs8IMeg7_oNXC4Ee81-X7MklfsAVmcAkRfURspQP-y0qgk.jpg?size=862x602\&quality=96\&type=album)<br>

Посмотрим, что можно сделать со снимком. На вход передается снимок, размер выходного таргета и размер ***real\_size*** (реальный размер таргета). Указываем 400х300.&#x20;

![](https://sun9-83.userapi.com/s/v1/if2/F-N0DSqqxAoGdmf4a6YCVsOgPRm-Oo1ctNuNndikNA5N7Vy7HonWERMmjEMa5huXKbY4om4hOU3NMI5GGZb-6qMQ.jpg?size=880x618\&quality=96\&type=album)<br>

Чтобы улучшить распознавание в базе, перед тем как загружать изображение, применим функцию ***zip\_img.*** Ранее был создан массив изображений, но все эти изображения были промасштабированы к тому размеру, которому мы хотели. Загрузим снимок и попробуем его распознавать с помощью нашей базы.

![](https://sun9-48.userapi.com/s/v1/if2/U6OOxGaY8-qZtBtKk_8tiiqmkniobTcvBt9A004gngsXLOdA1vQ_7xtDBMo6By4LkN8kk4qpIBBB8NVgT_2W4T3j.jpg?size=792x1080\&quality=96\&type=album)<br>

**Дополнительные источники информации:**

1. [Пакет NumPy](https://youtu.be/eDuuKvIWzew)
2. [Библиотека Matplotlib в Python](https://pythonim.ru/libraries/biblioteka-matplotlib-v-python)
3. [Шпаргалка по Matplotlib](https://proglib.io/p/vasha-povsednevnaya-shpargalka-po-matplotlib-2021-02-04)
4. [Учебник по библиотеке NumPy: учитесь на примерах](https://pythonist.ru/uchebnik-po-biblioteke-numpy-uchites-na-primerah/)
5. [Библиотека Matplotlib](https://devpractice.ru/files/books/python/Matplotlib.book.pdf)

**Задание:** Сейчас в функции zip\_img, параметры real\_size подбираются вручную. Задание - придумать алгоритм для вычисления этого параметра. <br>

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