5.9. Арифметичні операції

Сімейство функцій малювання з попереднього розділу малює у зображення. Арифметичне сімейство комбінує два зображення в третє – додає значення їхніх пікселів, віднімає одне від одного, обирає мінімум або максимум на кожній позиції. Цей невеликий набір попіксельних арифметичних операцій є основою різниці кадрів, віднімання фону, складання витримки та ряду інших класичних шаблонів.

Арифметичне сімейство класу Image достатньо мале, щоб перерахувати його повністю:

  • add() – попіксельне self + other, обрізане до максимуму формату.

  • sub() – попіксельне self - other, обрізане до 0 знизу.

  • rsub() – попіксельне other - self, обрізане до 0 (та сама арифметика, що й sub, але з переставленими операндами).

  • min() – попіксельний мінімум двох значень.

  • max() – попіксельний максимум.

  • difference() – попіксельне |self - other|, абсолютна різниця.

Плюс дві пов’язані операції над одним зображенням:

  • invert() – замінює кожен піксель на 255 - pixel (або еквівалентний максимум для формату).

  • negate() – псевдонім для invert().

Two horizontal gradient bars at the top representing source images A and B -- A going dark to bright left-to-right, B going bright to dark left-to-right. Below them, five gradient bars representing the result of each pairwise operation applied to A and B: A.add(B) appears uniform white because every position sums past 255 and clips; A.sub(B) is zero on the left half and brightens toward the right; A.difference(B) shows a V shape, bright on each end and dark in the middle; A.min(B) is dark on the ends and brighter in the middle; A.max(B) is bright on the ends and grey in the middle.

Два вихідних градієнти A і B та результат кожної попарної операції, застосованої до них. Кожна операція виконується позиція за позицією – те, що показано в результаті в будь-якому місці, залежить лише від двох вихідних пікселів на тій позиції.

5.9.1. Дві форми операнда

Кожен із двоіменних методів приймає будь-яку з двох форм для свого другого операнда:

  • Інший Image тих самих розмірів. Арифметика виконується позиція за позицією – результат на (x, y) – це операція, застосована до вихідних пікселів на (x, y) обох зображень.

  • Скалярне значення – ціле число для відтінків сірого, кортеж (r, g, b) для RGB565. Той самий скаляр застосовується на кожній позиції.

Скалярна форма корисна, коли застосунок хоче зсунути кожен піксель на постійну величину. img.add(40) освітлює все зображення на 40; img.sub((20, 20, 20)) затемнює кожен піксель на 20 на канал; img.max(50) піднімає будь-який піксель нижче 50 до значення 50 і залишає інші незмінними – такий тип операції, що перетворює майже чорний рівень датчика на рівномірний темно-сірий для наступних етапів обробки.

5.9.2. Відсікання

Значення пікселів залишаються в межах діапазону формату після кожної операції. Для 8-бітного каналу це означає 0255: будь-що, що перевищило б 255, відсікається до 255, а будь-що, що опустилося б нижче 0, обрізається до 0. Переповнення по колу відсутнє.

Цей вибір має практичне значення. add при освітленні пікселів ніколи не створює раптового артефакту потемніння на яскравому кінці, де математика інакше дала б переповнення; sub при затемненні пікселів ніколи не створює раптового артефакту освітлення на темному кінці, де б інакше стався недотік. Результати залишаються візуально значущими ціною деякої втрати інформації на насичених крайніх значеннях.

Відсікання також пояснює, чому sub і rsub повертають різні результати. img_a.sub(img_b) дає частину a, яка яскравіша за b, і нуль у всіх інших місцях; img_a.rsub(img_b) дає частину b, яка яскравіша за a. Обидва корисні для однобічного виявлення змін – якщо застосунок цікавлять лише пікселі, що стали яскравішими, або лише ті, що стали темнішими – але жоден не вловлює всіх змін між двома кадрами.

5.9.3. Операція різниці

Для двобічного виявлення змін слід використовувати difference(), яка обчислює |self - other| на кожній позиції – абсолютну різницю без знаку. Кожен піксель, що змінився в будь-якому напрямку, з’являється як ненульове значення в результаті, а величина пропорційна тому, наскільки він змінився на тій позиції.

Ця властивість – ненульове значення саме там, де два зображення не збігаються – робить difference робочим конем попіксельного виявлення змін. Еталонний кадр, збережений при запуску, і свіжий знімок, оброблені через difference, дають зображення, ненульові пікселі якого позначають кожну позицію, де щось у сцені перемістилося або змінило яскравість.

5.9.4. Обмеження за допомогою маски

Усі арифметичні методи приймають аргумент mask, описаний на сторінці «Регіони та маски». Коли передано маску, операція виконується лише на тих позиціях, де маска ненульова; скрізь інде цільове зображення залишається незмінним.

Ця схема використовується у двох шаблонах. Перший – обмеження операції до відомої ділянки: наприклад, додавання двох кадрів лише всередині обмежувального прямокутника виявленого маркера. Другий – побудова складеного кадру по частинах – min по послідовності кадрів всередині маски переднього плану, max по тій самій послідовності всередині доповнюючої маски – такий тип шаблону.

5.9.5. На місці та збереження вхідних даних

Арифметичні методи дотримуються операційної конвенції, встановленої раніше: кожен модифікує вихідне зображення на місці та повертає те саме зображення для ланцюгового виклику. Пікселі джерела зникають після виклику – замінюються результатом операції над тим, що було передано як другий операнд.

Коли застосунку потрібно зберегти обидва входи, безпечний шаблон – спочатку скопіювати один із них:

diff = current.copy()       # leaves current intact
diff.difference(reference)  # diff now holds the absolute difference

Цей шаблон – копіювати, потім оперувати – є основою будь-якого конвеєра різниці кадрів, де еталонний кадр повинен витримати порівняння, щоб його можна було повторно використати на наступному захопленому кадрі.

Маючи шість операцій комбінування, дві операції над одним зображенням, робочого коня абсолютної різниці та ключове слово mask для обмеження, набір інструментів попіксельної арифметики охоплює комбінації яскравості та каналів, необхідні класичному технічному зору. Решта інструментів, подібних до арифметичних, на поверхні працюють побітно, а не з цілими значеннями.