Почему билинейное масштабирование изображений с помощью PIL и pytorch дает разные результаты? - PullRequest
2 голосов
/ 31 марта 2020

Чтобы передать изображение в сеть Pytorch, мне сначала нужно уменьшить его до фиксированного размера. Сначала я сделал это с помощью метода PIL.Image.resize () с режимом интерполяции BILINEAR. Тогда я подумал, что было бы удобнее сначала преобразовать пакет изображений в тензор Pytorch, а затем использовать функцию torch.nn.functional.interpolate (), чтобы масштабировать весь тензор сразу на GPU (также «билинейный» режим интерполяции) , Это привело к снижению точности модели, потому что теперь во время вывода тип масштабирования (факел) отличался от того, который использовался во время обучения (PIL). После этого я сравнил два метода уменьшения масштаба визуально и обнаружил, что они дают разные результаты. Уменьшение размера подушки кажется более плавным. Эти методы выполняют различные операции под капотом, хотя оба являются билинейными? Если так, мне также любопытно, есть ли способ достигнуть того же самого результата как масштабирование изображения подушки с масштабированием тензора факела?

Исходное изображение (знаменитое изображение Ленны)

Масштабированное изображение подушки:

Pillow scaled image

Изображение с масштабированием факела:

Torch scaled image

Карта абсолютных разностей средних каналов:

Mean channel absolute difference map

Демонстрационный код:

import numpy as np
from PIL import Image
import torch
import torch.nn.functional as F
from torchvision import transforms
import matplotlib.pyplot as plt

pil_to_torch = transforms.ToTensor()
res_shape = (128, 128)


pil_img = Image.open('Lenna.png')
torch_img = pil_to_torch(pil_img)

pil_image_scaled = pil_img.resize(res_shape, Image.BILINEAR)
torch_img_scaled = F.interpolate(torch_img.unsqueeze(0), res_shape, mode='bilinear').squeeze(0)

pil_image_scaled_on_torch = pil_to_torch(pil_image_scaled)
relative_diff = torch.abs((pil_image_scaled_on_torch - torch_img_scaled) / pil_image_scaled_on_torch).mean().item()
print('relative pixel diff:', relative_diff)

pil_image_scaled_numpy = pil_image_scaled_on_torch.cpu().numpy().transpose([1, 2, 0])
torch_img_scaled_numpy = torch_img_scaled.cpu().numpy().transpose([1, 2, 0])
plt.imsave('pil_scaled.png', pil_image_scaled_numpy)
plt.imsave('torch_scaled.png', torch_img_scaled_numpy)
plt.imsave('mean_diff.png', np.abs(pil_image_scaled_numpy - torch_img_scaled_numpy).mean(-1))

Python 3.6.6, требования:

cycler==0.10.0
kiwisolver==1.1.0
matplotlib==3.2.1
numpy==1.18.2
Pillow==7.0.0
pyparsing==2.4.6
python-dateutil==2.8.1
six==1.14.0
torch==1.4.0
torchvision==0.5.0

1 Ответ

1 голос
/ 01 апреля 2020

«Билинейная интерполяция» - это метод интерполяции.

Но уменьшение масштаба изображения не обязательно выполняется только с использованием интерполяции.

Можно просто повторно сэмплировать изображение с более низкой частотой дискретизации, использование метода интерполяции для вычисления новых выборок, которые не совпадают со старыми выборками. Но это приводит к наложению алиасов (это то, что вы получаете, когда высокочастотные компоненты в изображении не могут быть представлены при более низкой плотности выборки, «налагая» энергию этих более высоких частот на низкочастотные компоненты; то есть новые низкочастотные компоненты появляются в изображение после повторной выборки).

Чтобы избежать наложения псевдонимов, некоторые библиотеки применяют фильтр нижних частот (удаляют высокие частоты, которые не могут быть представлены на более низкой частоте дискретизации) перед повторной выборкой. Алгоритм подвыборки в этих библиотеках делает гораздо больше, чем просто интерполяция.

Разница, которую вы видите, состоит в том, что эти две библиотеки используют разные подходы: одна пытается избежать наложения псевдонимов с помощью фильтрации нижних частот, а другая - нет.

Чтобы получить такие же результаты в Pillow, вам необходимо явно отфильтровать изображение в низких частотах самостоятельно. Чтобы получить идентичные результаты, вам нужно выяснить, как именно факел фильтрует изображение, есть разные методы и разные возможные настройки параметров. Просмотр исходного кода - лучший способ узнать, что именно они делают.

...