visdatcompy 0.8.4
Библиотека для сравнения визуальных наборов данных
Requires Python: >=3.12

# Библиотека для сравнения визуальных наборов данных

![visdatcompy](https://raw.githubusercontent.com/cloudysock/visdatcompy/main/static/logo.png)

## 📄 Описание

Этот проект разрабатывался как **удобный инструментарий для оптимизации обучения нейронных сетей**, основной задачей которого была **ликвидация повторного обучения нейросетей при высокой степени схожести изображений**, но после реализации основного функционала библиотека пополнилась удобной структурой и классами, позволяющими не только сравнивать изображения и датасеты по многим самым часто используемым метрикам и методам, но и **удобно работать с изображениями и датасетами в любых других целях.**

```python
# Welcome to visdatcompy!

img = Image(r"datasets\dataset\image.jpg")
dts = Dataset(r"datasets\dataset")

img.info()
dts.info()

> [V] Image Information:
> [$] Название изображения: image.jpg
> [$] Разрешение изображения: 6000 x 4000 x 3

> [V] Dataset Information:
> [%] Название датасета: dataset
> [%] Количество изображений: 322
> [%] Путь к датасету: datasets\dataset
```

## 😞 Проблема

Обучение нейросети занимает очень много времени. Сравнение датасетов позволит оценить их схожесть, а значит не обучать нейросеть заново при высоком сходстве. При работе с изображениями не было удобного инструмента для сравнения изображений по метаданным и метрикам.

## 🥇 Наше решение

### <p id="exif">1. **Сравнение по метаданным** 🔍</p>

Любой тип файла (звук, текст, изображение, видео) имеет свои стандарты метаданных.
Для цифровых фотографий, в основном, используют:

-   **EXIF** _(Exchangeable Image File Format)_ — техническая информация о деталях съемки сделанная фотокамерой;
-   **XMP** _(eXtensible Metadata Platform)_ — стандарт, разработанный Adobe позволяющий включать любую информацию;
-   **Свойства файла** — дополнительные параметры, являющиеся неотъемлемой частью фото.

При выстраивании логики сравнения было найдено оптимальное решение для отсеивания полных дубликатов с минимальной затратой времени - сравнение по exif-данным. Функционал для работы с exif-данными изображений в visdatcompy может быть использован как в личных целях пользователей, так и для нахождения дубликатов изображений.

**Пример извлечения метаданных изображения:**

```python
# Создаём объект класса изображения
img = Image(r"datasets\dataset\image.jpg")

# Извлекаем exif-данные в аттрибут exif_data
img.get_exif_data()

# Выводим значение полученного аттрибута (словаря)
print(img.exif_data)

> 'ResolutionUnit': 2,
> 'ExifOffset': 364,
> 'Make': 'SONY',
> 'Model': 'ILCE-6000',
> 'Software': 'ILCE-6000 v2.00',
> 'DateTime': '2017:06:11 11:39:36'
                ...
```

**Пример извлечения метаданных датасета:**

```python
# Создаём объект класса датасет
dataset = Dataset(r"datasets\dataset")

# Извлекаем exif-данные в аттрибут exif_data
dataset.get_exif_data()

# Выводим значение полученного аттрибута (pd.DataFrame)
print(dataset.exif_data)

> ...
```

### 2. **Сравнение по метрикам** 📊

**Метрика** - расстояние, определённое для любых двух элементов (точек) некоторого множества X. То есть это функция, которая возвращает расстояние между двумя объектами. Благодаря этому свойству мы можем расположить объекты от "идентичны" до "абсолютно разные".

#### **Диапазоны и описание:**

| Метрика  | Диапазон значений | Описание                                        |
| -------- | ----------------- | ----------------------------------------------- |
| PixToPix | True/False        | Попиксельное сравнение двух изображений         |
| MSE      | [0; ∞)            | Среднеквадратичная ошибка между изображениями   |
| NRMSE    | [0, 1]            | Нормализованная среднеквадратическая ошибка     |
| SSIM     | [-1;1]            | Структурное сходство изображений                |
| PSNR     | (0; ∞)            | Отношение максимального значения сигнала к шуму |
| MAE      | [0; ∞)            | Средняя абсолютная ошибка между изображениями   |
| NMI      | [1;2]             | Нормализованный показатель взаимной информации  |

_Pixel to pixel (pix2pix) не является полноправной метрикой, так как по сути своей это полное сравнение всех пикселей двух изображений между собой, однако для удобства был реализован в классе `Metrics`. Выходными данными этого метода является булево значение: `True` при полной схожести и `False` если есть различие. Его с лёгкостью заменяет [**сравнение по метаданным**](#exif)._

**Пример сравнения двух датасетов по метрике:**

```python
# Создаём объекты двух датасетов
dataset1 = Dataset(r"datasets\first_dataset")
dataset2 = Dataset(r"datasets\second_dataset")

# Создаём объект класса Metrics для работы с метриками
metrics = Metrics(dataset1, dataset2, r"results/metrics_results")

# Сохраняем результат сравнения двух датасетов
mae_result = metrics.mae(echo=True, to_csv=True)

# Визуализируем результат
metrics.show(mae_result)
```

<p align="center">
    <img src="https://raw.githubusercontent.com/cloudysock/visdatcompy/main/static/screenshots/metric_result.png" alt="MAE Result" title="MAE Result">
</p>

### 3. **Сравнение на основе Дескрипторов** 🎯

#### SIFT

**Метод SIFT** _(Scale-Invariant feature transform — масштабно-инвариантная трансформация признаков)_ содержит детекторы для определения интересующих нас характерных точек на изображении и отбрасывании низкоконтрастных ключевых точек. Выходной величиной является представление соседней с характерной точкой области в виде вектора дескрипторов.

<p align="center">
    <img src="https://raw.githubusercontent.com/cloudysock/visdatcompy/main/static/screenshots/sift_keypoints.png">
</p>

<p align="center">
    <img src="https://raw.githubusercontent.com/cloudysock/visdatcompy/main/static/screenshots/sift.png">
</p>

**Пример работы с SIFT:**

```python
from visdatcompy import Dataset, FeatureExtractor

# Создаём два объекта с датасетами
dataset1 = Dataset("../datasets/cows")
dataset2 = Dataset("../datasets/cows_duplicates")

# Создаём объект класса FeatureExtractor для работы с методом SIFT:
fext = FeatureExtractor(dataset1, dataset2, "sift")

# Ищем схожие изображения
fext.find_similars()
print(fext.sift_similars)
```

*В результате получаем атрибут в виде словаря, где ключи - объекты изображений из первого датасета, а значения - объекты изображений из второго датасета, являющиеся схожими.*

#### ORB

**ORB** _(Oriented FAST and Rotated BRIEF)_ - Ориентированный алгоритм быстрого обнаружения особенностей и вращенных бинарных инвариантных характеристик.

> *Работа с ORB отличается от работы с SIFT только аргументом, передаваемым в функцию.*

#### FAST

**FAST** _(Features from Accelerated Segment Test)_ - Быстрый алгоритм обнаружения особенностей.

> *Работа с FAST отличается от работы с SIFT только аргументом, передаваемым в функцию.*

### 4. **Сравнение на основе Хэшей** 🧮

**Пример сравнения двух датасетов на основе хэшей:**

```python
# Создаём два объекта класса Dataset
dataset1 = Dataset(r"datasets\first_dataset")
dataset2 = Dataset(r"datasets\second_dataset")

# Создаём объект класса HASH для сравнения двух датасетов
hash = Hash(dataset1, dataset2)

# Находим схожие изображения и экспортируем результат в csv файл
Hash.find_similars("average", to_csv=True)
```

| Характеристика     | Описание                                                                                                                                          |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| AverageHash        | Рассчитывает хэш-значение на основе среднего значения пикселей, быстрый алгоритм хэширования изображений, но подходит только для простых случаев. |
| PHash              | Улучшенная версия AverageHash, медленнее чем AverageHash, но может адаптироваться к более широкому спектру ситуаций.                              |
| MarrHildrethHash   | Значение хэша рассчитывается на основе оператора граней Марра-Хилдрета, что является самым медленным, но более дискриминативным методом.          |
| RadialVarianceHash | Рассчитывает хэш-значение на основе преобразования Радона.                                                                                        |
| BlockMeanHash      | Рассчитывает хэш-значение на основе среднего значения блоков, представленного в том же статье, что и MarrHildrethHash.                            |
| ColorMomentHash    | Рассчитывает хэш-значение на основе моментов цвета, представленного в той же статье, что и RadialVarianceHash.                                    |

### 5. **Главный класс для поиска дубликатов и схожестей** ⚖️

**Для объединения всех методов поиска дубликатов и схожих изображений мы реализовали весь главный функционал в одном классе VisDatCompare:**

```python
# Создаём объекты класса Dataset
dataset1 = Dataset("datasets/drone")
dataset2 = Dataset("datasets/drone_duplicates")

# Создаём объект класса VisDatCompare поиска дублей и схожестей
compy = VisDatCompare(dataset1, dataset2)

# Ищем дубликаты изображений методом MSE:
compy.duplicates_finder.find_metrics_duplicates("mse")
# Удаляем дубликаты
compy.duplicates_finder.clear_duplicates()

# Ищем схожие изображения с помощью SIFT:
compy.similars_finder.find_features_similars("sift")
# Удаляем схожие изображения
compy.similars_finder.clear_similars()
```

**Таким образом буквально в несколько строк мы можем реализовать оптимальную логику:**

1. Быстро отсеять дубликаты по exif-характеристикам
2. Убрать не несущие в себе exif-данные, дубликаты изображений методом Pixel to Pixel или с помощью метрик.
3. Определить уже среди оставшихся изображений схожие по нескольким методам и также их удалить при необходимости.

## 🛠️ **Установка**

### Простая установка библиотеки:

```powershell
> pip install visdatcompy
```

### Установка последней версии разработки в режиме редактирования:

#### 1. Клонирование репозитория 📂

Переходим в нужную директорию и клонируем репозиторий:

```powershell
> git clone https://github.com/maxfraid/visdatcompy.git
```

#### 2. Настройка виртуального окружения 📦

Перед работой с библиотекой рекомендуется настроить виртуальное окружение для последующей работы в нём.

**1. Переходим в корень проекта:**

```powershell
> cd visdatcompy
```

**2. Создаём виртуальное окружение:**

```powershell
> python -m venv .venv
```

**3. Активируем его:**

```powershell
> .venv\Scripts\activate.bat
```

#### 3. Установка зависимостей 🧩

Перед началом работы с библиотекой необходимо также установить вспомогательные библиотеки из файла зависимостей:

```powershell
> pip install -r requirements.txt        
```

#### 4. Установка библиотеки в режиме редактирования 📥

Последним этапом необходимо установить библиотеку в режиме редактирования:

```powershell
> pip install -e .
```

## 📬 **Обратная связь**

По всем вопросам: **ferjenkill@gmail.com**