Размытие рамки не быстрее, чем размытие по Гауссу?

Я написал код для применения фильтров к изображению с использованием свертки ядра. В настоящее время для изображения размером 400x400 требуется довольно много времени, примерно 30 секунд. Я понимаю, что размытие рамки намного быстрее, чем размытие по Гауссу. Однако, когда я меняю ядро ​​на размытие по рамке, кажется, что это занимает столько же времени, сколько и размытие по Гауссу. Любые идеи?

import cv2
import numpy as np

img = cv2.imread('test.jpg')
img2 = cv2.imread('test.jpg')

height, width, channels = img.shape

GB3 = np.array([[1,2,1], [2,4,2], [1,2,1]])
GB5 = np.array([[1,4,6,4,1], [4,16,24,16,4], [6,24,36,24,6], [4,16,24,16,4], [1,4,6,4,1]])
BB = np.array([[1,1,1], [1,1,1], [1,1,1]])

kernel = BB

#initialise
kernel_sum = 1

filtered_sum_r = 0 
filtered_sum_g = 0 
filtered_sum_b = 0 


for i in range(kernel.shape[0]):
    for j in range(kernel.shape[1]):
        p = kernel[i][j]
        kernel_sum += p 

for x in range(1,width-1):
    for y in range(1,height-1):
        for i in range(kernel.shape[0]):
            for j in range(kernel.shape[1]):
                filtered_sum_b += img[y-1+j,x-1+i,0]*kernel[i][j]
                filtered_sum_g += img[y-1+j,x-1+i,1]*kernel[i][j]
                filtered_sum_r += img[y-1+j,x-1+i,2]*kernel[i][j]
        
        new_pixel_r = filtered_sum_r/kernel_sum
        new_pixel_g = filtered_sum_g/kernel_sum
        new_pixel_b = filtered_sum_b/kernel_sum

        if new_pixel_r>255:
            new_pixel_r = 255
        elif new_pixel_r<0: 
            new_pixel_r = 0

        if new_pixel_g>255:
            new_pixel_g = 255
        elif new_pixel_g<0: 
            new_pixel_g = 0

        if new_pixel_b>255:
            new_pixel_b = 255
        elif new_pixel_b<0: 
            new_pixel_b = 0

        img2[y,x,0] = new_pixel_b
        img2[y,x,1] = new_pixel_g
        img2[y,x,2] = new_pixel_r

        filtered_sum_r = 0 
        filtered_sum_g = 0 
        filtered_sum_b = 0 
        #print(kernel_sum)

scale = 2
img_big = cv2.resize(img, (0,0), fx=scale, fy=scale) 
img2_big = cv2.resize(img2, (0,0), fx=scale, fy=scale) 


cv2.imshow('original', img_big)
cv2.imshow('processed', img2_big)

cv2.waitKey(0)
cv2.destroyAllWindows()

person Community    schedule 04.12.2020    source источник
comment
если прямоугольный фильтр имеет тот же размер и такое же количество операций, он выполняется так же быстро, как и свертка. Одним из преимуществ блочного фильтра является то, что вы можете использовать интегральные изображения для предварительного вычисления большого количества информации, так что блочный фильтр большего размера может быть вычислен очень эффективно и в основном независимо от размера фильтра. Кроме того, я хотел бы предложить вам использовать функции opencv вместо того, чтобы самостоятельно реализовывать фильтры, поскольку opencv имеет много оптимизаций, таких как инструкции SSE, интегральные изображения и т. Д.   -  person Micka    schedule 04.12.2020


Ответы (1)


  • вы используете петли Python. это всегда будет на порядки медленнее, чем оптимизированный двоичный код. по возможности используйте библиотечные функции, например numpy и OpenCV. или напишите свой критический код как компилируемый Cython.
  • модель доступа вашего кода неоптимальна. вы должны перемещаться по строкам во внутреннем цикле (для y: для x :), потому что так хранится изображение. причина здесь в том, как используется кеш вашего процессора. в главном хранилище строк строка кэша содержит несколько пикселей подряд. если вы работаете по столбцам, вы используете эту строку кэша только один раз, прежде чем понадобится другая.
  • в вашем коде не используется то свойство, что оба типа фильтра разделяются
  • свертку можно выразить как поэлементное умножение в частотной области (ДПФ, умножение, обратное ДПФ), что является обычным способом выполнения сверток.

Используйте функцию OpenCV filter2D для ваших сверток.

Что касается размытия рамки по сравнению с гауссовским, единственная разница - интересный вес по сравнению с отсутствием весов (все равны). Это означает еще несколько умножений или нет. Когда код оптимизирован, время его выполнения может зависеть от времени, необходимого для передачи данных из ОЗУ в ЦП. это касается оптимизированного кода, а не чистых циклов Python.

person Christoph Rackwitz    schedule 04.12.2020