5.21. Масштабування, відображення та обрізання¶
Попередні підрозділи працювали з пікселями на тих самих позиціях, де вони знаходилися спочатку. Сімейство перетворень змінює це. Масштабування надсилає кожен вхідний піксель на іншу вихідну позицію – можливо, на кілька вихідних позицій одночасно (при збільшенні) або на позицію, спільну для кількох вхідних пікселів (при зменшенні). Відображення і обертання роблять те саме через інше відображення. Обрізання зберігає прямокутну підмножину вхідних пікселів і відкидає решту.
Модуль image надає цю функціональність через три методи, які поділяють більшість аргументів і більшість поведінки:
copy()– створює копію зображення, можливо масштабовану, обрізану або переорієнтовану.crop()– та сама операція, що йcopy, але з очікуванням, що застосунок вибере підпрямокутник із джерела.scale()– те саме, з очікуванням, що застосунок змінить розмір результату.
Усі три мають однакові аргументи і однакову машинерію перетворень; різниця полягає в тому, куди за замовчуванням потрапляє результат. copy() створює нове зображення, тоді як crop() та scale() змінюють джерело на місці.
5.21.2. Інтерполяція: AREA, BILINEAR, BICUBIC¶
Коли масштабування надсилає кожен вихідний піксель на позицію, яка не збігається з жодним окремим вхідним пікселем, метод має вирішити, яке значення записати. Три прапори контролюють цей процес:
image.BILINEAR інтерполює між чотирма найближчими вхідними пікселями, зважуючи за відстанню від вихідної позиції. Результат плавніший, ніж при найближчому сусідові, без видимих зубців на діагональних лініях, але додаткові обчислення коштують приблизно вчетверо більше, ніж прохід найближчого сусіда. Правильний вибір для більшості робіт із збільшенням і для будь-якого нецілочисельного масштабного коефіцієнта.
image.BICUBIC інтерполює між шістнадцятьма найближчими вхідними пікселями за допомогою кубічної кривої, що дає ще плавніші результати за рахунок більших обчислень. Найкраща якість для чутливих до ресурсів застосунків, яким вона потрібна; рідко варте додаткових обчислень для живих кадрів, які IDE лише відображатиме.
image.AREA усереднює кожен вхідний піксель, що потрапляє у відбиток вихідного пікселя – правильний алгоритм для зменшення масштабу. Білінійна і бікубічна інтерполяції оцінюють значення між пікселями джерела, що саме й потрібно при збільшенні; але при зменшенні кожен вихідний піксель охоплює багато пікселів джерела, а інтерполятор зчитує лише кілька найближчих – пропущені деталі повертаються як артефакти. image.AREA включає всі охоплені пікселі в середнє значення.
Алгоритм масштабування за замовчуванням без підказок – найближчий сусід, який є найдешевшим і правильним вибором, коли джерело вже має роздільну здатність призначення.
5.21.3. Орієнтація: відображення та обертання¶
Прапори орієнтації – це невеликий набір булевих перетворень, які вільно поєднуються між собою та з прапорами інтерполяції:
image.VFLIPвідображає зображення вертикально (верх стає низом).image.HMIRRORвідображає його горизонтально (ліво стає правом).image.TRANSPOSEміняє місцями осі x і y (рядки стають стовпцями).
Більшість обертань отримують поєднанням цих трьох. Модуль також надає іменовані скорочення:
image.ROTATE_90(=VFLIP | TRANSPOSE)image.ROTATE_180(=HMIRROR | VFLIP)image.ROTATE_270(=HMIRROR | TRANSPOSE)
У коді:
img.copy(hint=image.ROTATE_90, copy_to_fb=True)
5.21.4. Обробка пропорцій¶
Коли пропорції джерела не збігаються з прямокутником, у який воно відмальовується, три прапори вирішують, що робити з цією розбіжністю:
image.SCALE_ASPECT_KEEP зберігає пропорції джерела і додає рамки до результату – джерело масштабується до розміру всередині призначення, а порожні (нульові) пікселі заповнюють решту призначення. Правильний вибір, коли збереження джерела без спотворень важливіше за заповнення всього виходу.
image.SCALE_ASPECT_EXPAND зберігає пропорції джерела і обрізає його – джерело масштабується до заповнення призначення, а частини, що виходять за межі призначення, відрізаються. Правильний вибір, коли заповнення всього виходу важливіше за відображення кожної частини джерела.
image.SCALE_ASPECT_IGNORE ігнорує пропорції і розтягує джерело до заповнення призначення, погоджуючись на будь-яке спотворення. Правильний вибір, коли застосунок уже врахував спотворення – наприклад, коли розміри призначення насправді не є прямокутником тієї самої сцени.
За замовчуванням (прапор пропорцій не встановлено) – те саме, що й SCALE_ASPECT_IGNORE: розтягнути до заповнення. Застосунки, що дбають про пропорції, явно вказують один із трьох прапорів.
5.21.5. Коли яким методом користуватися¶
Більшість змін розміру використовують scale() з парою x_scale / y_scale та підказкою інтерполяції:
img.scale(x_scale=0.5, y_scale=0.5, hint=image.AREA)
Більшість обертань використовують той самий виклик з hint=image.ROTATE_90 або подібним.
Для обрізання використовують crop() з нестандартним roi:
img.crop(roi=(40, 30, 200, 150))
Коли джерело має вижити після операції – захоплення опорного кадру, створення мініатюри кадру, який ось-ось буде деструктивно оброблений – copy() повертає результат як нове зображення і залишає джерело незайманим:
thumbnail = img.copy(x_scale=0.25, y_scale=0.25, hint=image.AREA)
Цей стандартний підхід і є реальною різницею між трьома іменами: scale і crop перетворюють на місці, copy виділяє пам’ять. Ключові слова розміщення результату усувають цю різницю: copy=True у scale або crop виділяє результат як окремий буфер у купі замість перезапису джерела, а copy_to_fb=True у будь-якому з трьох розміщує його у кадровому буфері для попереднього перегляду в IDE.