Средний геометрический фильтр с OpenCV

Я хочу применить средний геометрический фильтр к изображению в opencv (python). Есть ли встроенная функция или я должен сам реализовать фильтр? Каков наиболее эффективный способ реализации нелинейного фильтра в opencv?

1 ответ

Решение

Напомним из логарифмических тождеств

log((x1 * x2 * ... * xn)^(1/n)) = (1/n) * (log(x1) + log(x2) + ... + log(xn))

Из Википедии:

Среднее геометрическое также может быть выражено как экспонента среднего арифметического от логарифмов. Используя логарифмические тождества для преобразования формулы, умножения могут быть выражены как сумма, а степень - как умножение.

Это означает, что геометрическое среднее можно просто рассчитать как среднее арифметическое, т.е. cv2.boxFilter() логарифма значений изображения. Тогда вы просто возвеличите результат и все готово!

Например, давайте проверим ручной метод и этот метод и проверим результаты. Сначала загрузите изображение и определите размер ядра:

import cv2
import numpy as np

img = cv2.imread('cameraman.png', cv2.IMREAD_GRAYSCALE).astype(float)
rows, cols = img.shape[:2]
ksize = 5

кинооператор

Далее давайте дополним изображение и вычислим среднее геометрическое вручную:

padsize = int((ksize-1)/2)
pad_img = cv2.copyMakeBorder(img, *[padsize]*4, cv2.BORDER_DEFAULT)
geomean1 = np.zeros_like(img)
for r in range(rows):
    for c in range(cols):
        geomean1[r, c] = np.prod(pad_img[r:r+ksize, c:c+ksize])**(1/(ksize**2))
geomean1 = np.uint8(geomean1)
cv2.imshow('1', geomean1)
cv2.waitKey()

Среднее геометрическое 1

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

geomean2 = np.uint8(np.exp(cv2.boxFilter(np.log(img), -1, (ksize, ksize))))
cv2.imshow('2', geomean2)
cv2.waitKey()

Среднее геометрическое 2

Ну, они, конечно, выглядят одинаково. На самом деле я обманул, это то же самое загруженное изображение, что и выше. Но это нормально, потому что:

print(np.array_equal(geomean1, geomean2))

Правда

Другие вопросы по тегам