OpenCV — cравнение алгоритмов интерполяции при изменении размеров изображения


OpenCV

Изменение размеров (масштабирование / scaling) — это очень часто используемый метод при работе с изображениями.
В OpenCV для выполнения этой задачи используется функция resize().

В C++:

void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )

В Python:

dst = cv2.resize( src, dsize[, dst[, fx[, fy[, interpolation]]]] )

Размер изображения можно либо указать вручную (dsize), либо передать коэффициенты масштабирования по соответствующим осям картинки: fx, fy.

height, width = img.shape[:2]
res = cv.resize(img, (2*width, 2*height), interpolation = cv.INTER_CUBIC)
# ИЛИ
res = cv.resize(img, None, fx=2, fy=2, interpolation = cv.INTER_CUBIC)

Параметр interpolation устанавливает один из нескольких возможных методов интерполяции:
cv.INTER_NEAREST — интерполяция методом ближайшего соседа (nearest-neighbor interpolation),
cv.INTER_LINEAR — билинейная интерполяция (bilinear interpolation (используется по умолчанию),
cv.INTER_CUBIC — бикубическая интерполяция (bicubic interpolation) в окрестности 4×4 пикселей,
cv.INTER_AREA — передискретизации с использованием отношения площади пикселя,
cv.INTER_LANCZOS4 — интерполяция Ланцоша (Lanczos interpolation) в окрестности 8×8 пикселей.

Для выбора метода — нужно разобраться — какой из этих методов лучше?
По умолчанию, интерполяция выполняется методом cv.INTER_LINEAR.
В официальном учебном пособии OpenCV (Geometric Transformations of Images) указывается, что:
* для сжатия изображения — наиболее предпочтительным методом интерполяции является cv.INTER_AREA,
* для увеличения изображения — наиболее предпочтительны методы интерполяции: cv.INTER_CUBIC (медленный) и cv.INTER_LINEAR.

Остаётся провести сравнение работы различных методов интерполяции, чтобы на практике проверить — какой их них лучше подходит для уменьшения или увеличения изображений.

Сравнение работы различных методов интерполяции при масштабировании изображений в OpenCV

Ниже приведены результаты доступных в OpenCV алгоритмов интерполяции при масштабировании изображений. Примеры показаны как для увеличения, так и для уменьшения размера изображения.

Подключаем нужные библиотеки:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

np.random.seed(42)

import seaborn as sns
plt.style.use('seaborn-white')
sns.set_context('notebook', rc={'figure.figsize': (10, 8)}, font_scale=1.5)

import cv2
print('OpenCV version:', cv2.__version__)
OpenCV version: 3.4.2

Загружаем тестовые картинки:

imgorig = cv2.imread('cat4.jpg')
imgorig2 = cv2.imread('cat2.jpg')
imgorig3 = cv2.imread('cat3.jpg')

img = cv2.cvtColor(imgorig, cv2.COLOR_BGR2RGB)
print(img.shape)

img2 = cv2.cvtColor(imgorig2, cv2.COLOR_BGR2RGB)
print(img2.shape)

img3 = cv2.cvtColor(imgorig3, cv2.COLOR_BGR2RGB)
print(img3.shape)
(224, 224, 3)
(278, 345, 3)
(385, 455, 3)

Задаём типы интерполяции:

interpolation_algorithm = [
    ("nearest", cv2.INTER_NEAREST),
    ("bilinear", cv2.INTER_LINEAR),
    ("bicubic", cv2.INTER_CUBIC),
    ("area", cv2.INTER_AREA),
    ("lanczos4", cv2.INTER_LANCZOS4)
]

Тестирование:

def resize_test(img, factor, is_plot=True, file_name=None):
    height, width, channels = img.shape
    height2, width2 = int(height*factor), int(width*factor)
    print('orig size:', height, width)
    print('resize size:', height2, width2)

    imgs = []
    for alg in interpolation_algorithm:
        img_r = cv2.resize(img, (width2, height2), interpolation = alg[1])
        imgs.append(img_r)

    if is_plot:
        plt.figure(figsize=(11, 2))
        plt.subplot(1, len(imgs)+1, 1)
        plt.title('orig')
        plt.imshow(img)
        plt.axis('off')
        for i in range( len(imgs) ):
            plt.subplot(1, len(imgs)+1, i+2)
            plt.title( interpolation_algorithm[i][0] )
            plt.imshow(imgs[i])
            plt.axis('off')
        plt.subplots_adjust(wspace=0)
        if file_name != None:
            plt.savefig(file_name)
        plt.show()

    return imgs

print('DOWN')
img_down0 = resize_test(img, 0.25, file_name='opencv_resize_down1.png')
img_down1 = resize_test(img2, 0.125, file_name='opencv_resize_down2.png')
img_down2 = resize_test(img3, 0.125, file_name='opencv_resize_down3.png')
print('UP')
img_up0 = resize_test(img_down0[3], 4, file_name='opencv_resize_up1.png')
img_up1 = resize_test(img_down1[3], 8, file_name='opencv_resize_up2.png')
img_up2 = resize_test(img_down2[3], 8, file_name='opencv_resize_up3.png')

Уменьшение

orig size: 224 224
resize size: 56 56
cравнение алгоритмов интерполяции при изменении размеров изображения
orig size: 278 345
resize size: 34 43
cравнение алгоритмов интерполяции при изменении размеров изображения
orig size: 385 455
resize size: 48 56
cравнение алгоритмов интерполяции при изменении размеров изображения

Увеличение

orig size: 56 56
resize size: 224 224
cравнение алгоритмов интерполяции при изменении размеров изображения
orig size: 34 43
resize size: 272 344
cравнение алгоритмов интерполяции при изменении размеров изображения
orig size: 48 56
resize size: 384 448
cравнение алгоритмов интерполяции при изменении размеров изображения

Сравнение скорости работы различных методов интерполяции при масштабировании изображений в OpenCV

Дополнительно рассмотрим сравнение скорости работы различных алгоритмов интерполяции.

import pandas as pd
import time

Выполним 50 раз процедуру изменения масштаба изображения с разным коэффициентом масштабирования и разными алгоритмами интерполяции:

n = 50
data = []
factors = [0.125, 0.25, 0.5, 0.75, 1.25, 1.5, 2, 3, 4, 6, 8, 10]
for alg in interpolation_algorithm:
    for factor in factors:
        times = []
        for i in range(n):
            t0 = time.time()
            cv2.resize(img, None, fx=factor, fy=factor, interpolation=alg[1])
            tdelta = (time.time()-t0)
            times.append(tdelta)
        mtime = np.mean(times)
        err = 2*np.std(times)
        data.append(dict(time=mtime, algorithm=alg[0], error=err, scale=factor))
df = pd.DataFrame(data)

ax = df.set_index('scale').groupby("algorithm")['time'].plot(legend=True, figsize=(10, 8), grid=True, title='Algorithm time compare')
ax[0].set_xlabel("scale factor")
ax[0].set_ylabel("mean time (sec)")

Полученное графическое представление скорости работы алгоритмов:
cравнение скорости работы алгоритмов интерполяции при изменении размеров изображения

Заключение

Полученные данные говорят сами за себя.
Для уменьшения масштаба изображения, лучше всего подходит метод cv2.INTER_AREA.
Для увеличения масштаба изображения, лучше всего подходят методы (расположены в порядке уменьшения скорости работы): cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_LANCZOS4.

За исключением cv2.INTER_LANCZOS4 — все методы имеют сравнимое время работы.
Однако cv2.INTER_CUBIC и cv2.INTER_LINEAR более медленные, чем cv2.INTER_AREA и cv2.INTER_NEAREST, а cv2.INTER_LANCZOS4 — самый медленный из всех алгоритмов.

Ссылки
Geometric Transformations of Images
resize()
Comparison of OpenCV Interpolation Algorithms

По теме
OpenCV шаг за шагом. Обработка изображения — изменение размеров


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна конкурс манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение