Лабораторная 13. Поиск похожих изображений
Требуется реализовать систему поиска похожих изображений. Работа выполняется в группах от 1 до 3 человек.
Работу необходимо вести в GitHub/GitLab репозитории.
Решение должно принимать на вход пользовательское изображение и возвращать список из K изображений, похожих на переданное.
В качестве признаков, извлекаемых из изображения, предлагается использовать ключевые точки.
Для реализации данного подхода рекомендуется выполнить следующие шаги:
- Собрать два набора изображений: первый для обучения классификатора дескрипторов ключевых точек (около 100-200 изображений, можно использовать COCO128 для этого), и второй уже для построения вашей базы (для хорошей работы системы следует использовать более 1000 изображений, например можно использовать Pascal VOC набор данных). Сбор данных можно производить и с помощью парсеров поисковиков изображений (Yandex Images, Google Images).
- Из изображений тренировочного набора данных извлечь ключевые точки (нужны будут только дескрипторы, локализация точек для данного алгоритма не важна). Для извлечения ключевых точек можно использовать алгоритм SIFT. Дескрипторы ключевых точек со всех изображений объединить в один массив. Таким образом получено тренировочное множество для следующего шага. Оно будет содержать около 200K дескрипторов. Если необходимо (в случае плохого качество системы) повысить репрезентативность данных, то следует извлечь ключевые точки из 1000+ разных изображений. Их будет достаточно много и на всех обучить модель из следующего шага будет проблематично. Поэтому следует случайным образом выбрать из этого множества около 200K дескрипторов для обучения. Поскольку случайно выбранные дескрипторы будут относиться к разным изображениям из 1000+, разнообразность регионов, которые описывают дескрипторы этих точек, возрастет.
- На данных, полученных в предыдущем шаге обучить модель кластеризации. Можно использовать K-Means (оптимальное количество кластеров 512-2048). Обученную модель можно сохранить и загружать с помощью библиотеки pickle для Python по следующей инструкции.
- Для реализации поиска необходимо реализовать функцию для представления изображения в виде вектора в метрическом пространстве. Можно использовать подход "мешок визуальных слов". Для этого необходимо извлечь ключевые точки из изображения, затем использовать классификатор из предыдущего шага для определения класса каждого дескриптора. Таким образом получится множество классов. Теперь можно построить гистограмму частоты вхождения каждого класса в данной изображений. Размер гистограммы будет составлять количество кластеров у K-Means. Данную гистограмму следует пронормировать. Таким образом получается функцию для кодирования изображения в вектор.
- Далее необходимо проиндексировать базу. Для этого нужно применить функцию из шага 4 ко всем изображениям из базы (1000+ изображений из пункта 2), и сохранить эти данные в базу с колонками ["уникальный индекс", "путь до файла изображения", "вектор кодировки"]. Можно хранить базу в csv таблице. С такой базой может быть удобно работать через Pandas.
- После получения базы можно перейти к реализации метода поиска в ней. На вход идёт изображение, которое кодируется функцией из шага 4. Затем необходимо найти k-ближайших элементов из базы. В качестве расстояния можно использовать косинусное расстояние. "Ручное" сравнение со всеми векторами из базы методом перебора всех вектором не будет являться оптимальным. Для реализации данного действия необходимо "обернуть" базу векторов методом ближайших соседей, реализация которой уже есть в scikit-learn . Теперь будет возможность быстрого поиска в пространстве векторов базы. После получения k-индексов ближайших изображений из базы, необходимо по найденным индексам получить пути до изображений, загрузить и вернуть их пользователю.
- Для реализации интерфейса необходимо использовать фреймвок Streamlit. С помощью него получится быстро и просто создать пользовательский интерфейс для демонстрации работы реализованной системы. С помощью Streamlit необходимо будет сделать форму для загрузки пользовательского изображения (документация), а также реализовать форму для выдачи списка похожих изображений из базы (документация).
Рекомендации:
- Для оптимизации поиска похожих изображений в базе можно использовать библиотеку Faiss.
- Чтобы загрузить изображение через Streamlit для удобства можно воспользоваться библиотекой pillow:
uploaded_file = st.file_uploader("Choose an image...", type=["png", "jpg", "jpeg", "webp", "tiff"])
image = PIL.Image.open(uploaded_file).convert("RGB")
image = PIL.ImageOps.exif_transpose(image)
При сдаче лабораторной работы командой необходимо демонстрировать страницу с веб-интерфейсов (сгенерированную Streamlit, или же можно сделать свою реализацию) и программный код в репозитории.