导向滤波算法原理与代码_ide

1. 导向滤波算法

导向图像(Guidance Image) I,滤波输出图像(Filtering Input Image) p,均值平滑窗口半径 r,正则化参数 e。

导向滤波算法原理与代码_ide_02

2. 快速导向滤波算法

通过下采样减少像素点,计算mean_a & mean_b后进行上采样恢复到原有的尺寸大小。

假设缩放比例为s,那么缩小后像素点的个数为N/s2,那么时间复杂度变为O(N/s2)

导向滤波算法原理与代码_ide_03

3. 代码

import cv2,math
import numpy as np
import pycuda.gpuarray as gpuarray
import pycuda.cumath as cumath
import pycuda.autoinit




def guideFilter(I, p, winSize, eps):
"""
导向图像(Guidance Image) I,滤波输出图像(Filtering Input Image) p,均值平滑窗口半径 r,正则化参数 e。
利用导向滤波进行图像平滑处理时,通常令p=I。
其中:guideFilter()函数调用opencv自带的库函数blur() 进行均值平滑。
:param I:
:param p:
:param winSize:
:param eps:
:return:
"""
# I的均值平滑
mean_I = cv2.blur(I, winSize)
# p的均值平滑
mean_p = cv2.blur(p, winSize)
# I*I和I*p的均值平滑
mean_II = cv2.blur(I * I, winSize)
mean_Ip = cv2.blur(I * p, winSize)
# 方差
var_I = mean_II - mean_I * mean_I # 方差公式
# 协方差
cov_Ip = mean_Ip - mean_I * mean_p
a = cov_Ip / (var_I + eps)
b = mean_p - a * mean_I
# 对a、b进行均值平滑
mean_a = cv2.blur(a, winSize)
mean_b = cv2.blur(b, winSize)
q = mean_a * I + mean_b
return q


def FastguideFilter(I, p, winSize, eps, s):
"""
快速导向滤波
通过下采样减少像素点,计算mean_a & mean_b后进行上采样恢复到原有的尺寸大小。
假设缩放比例为s,那么缩小后像素点的个数为N/s^2,那么时间复杂度变为O(N/s^2)
fmean代表均值平滑,fsubsample代表图像下采样即缩小图像,fupsample代表图片上采样即放大图像,s为缩小系数。
:param I:
:param p:
:param winSize:
:param eps:
:param s:
:return:
"""
# 输入图像的高、宽
h, w = I.shape[:2]

# 缩小图像
size = (int(round(w * s)), int(round(h * s)))

small_I = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)
small_p = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)

# 缩小滑动窗口
X = winSize[0]
small_winSize = (int(round(X * s)), int(round(X * s)))

# I的均值平滑
mean_small_I = cv2.blur(small_I, small_winSize)

# p的均值平滑
mean_small_p = cv2.blur(small_p, small_winSize)

# I*I和I*p的均值平滑
mean_small_II = cv2.blur(small_I * small_I, small_winSize)

mean_small_Ip = cv2.blur(small_I * small_p, small_winSize)

# 方差
var_small_I = mean_small_II - mean_small_I * mean_small_I # 方差公式

# 协方差
cov_small_Ip = mean_small_Ip - mean_small_I * mean_small_p

small_a = cov_small_Ip / (var_small_I + eps)
small_b = mean_small_p - small_a * mean_small_I

# 对a、b进行均值平滑
mean_small_a = cv2.blur(small_a, small_winSize)
mean_small_b = cv2.blur(small_b, small_winSize)

# 放大
size1 = (w, h)
mean_a = cv2.resize(mean_small_a, size1, interpolation=cv2.INTER_LINEAR)
mean_b = cv2.resize(mean_small_b, size1, interpolation=cv2.INTER_LINEAR)

q = mean_a * I + mean_b

return q

"""
下图导向滤波采用了r=16也就是winSize=(16,16), eps=0.01的参数大小。
快速导向滤波采用了r=16也就是winSize=(16,16), eps=0.01,s=0.5的参数大小。
"""
def run():
image = cv2.imread(r'/home/cheng/Documents/practice_py/cv/face03.png', cv2.IMREAD_ANYCOLOR)
#将图像归一化
image_0_1 = image/255.0

#导向滤波(三通道)
b, g, r = cv2.split(image_0_1)
# 1.753212477
# gf1 = guideFilter(b, b, (16,16), math.pow(0.1,2))
# gf2 = guideFilter(g, g, (16,16), math.pow(0.1,2))
# gf3 = guideFilter(r, r, (16,16), math.pow(0.1,2))
# 0.944390349
gf1 = FastguideFilter(b, b, (16, 16), math.pow(0.1, 2),s=0.5)
gf2 = FastguideFilter(g, g, (16, 16), math.pow(0.1, 2),s=0.5)
gf3 = FastguideFilter(r, r, (16, 16), math.pow(0.1, 2),s=0.5)
gf = cv2.merge([gf1, gf2, gf3])


#保存导向滤波结果
gf = gf*255
gf[gf>255] = 255
gf = np.round(gf)
gf = gf.astype(np.uint8)
res = np.hstack((image,gf))
cv2.imshow("res",res)
cv2.imwrite(r'/home/cheng/Documents/practice_py/cv/resface03.png.jpg', gf)
cv2.waitKey(0)


def gpu_run():
image = gpuarray.to_gpu(cv2.imread(r'/home/cheng/Documents/practice_py/cv/face03.png', cv2.IMREAD_ANYCOLOR))
#将图像归一化
image_0_1 = image/255.0

#导向滤波(三通道)
b, g, r = image_0_1[:,:,0],image_0_1[:,:,1],image_0_1[:,:,2]
# 1.753212477
# gf1 = guideFilter(b, b, (16,16), math.pow(0.1,2))
# gf2 = guideFilter(g, g, (16,16), math.pow(0.1,2))
# gf3 = guideFilter(r, r, (16,16), math.pow(0.1,2))
# 0.944390349
gf1 = FastguideFilter(b, b, (16, 16), math.pow(0.1, 2),s=0.5)
gf2 = FastguideFilter(g, g, (16, 16), math.pow(0.1, 2),s=0.5)
gf3 = FastguideFilter(r, r, (16, 16), math.pow(0.1, 2),s=0.5)
gf = cv2.merge([gf1, gf2, gf3])


#保存导向滤波结果
gf = gf*255
gf[gf>255] = 255
gf = np.round(gf)
gf = gf.astype(np.uint8)
res = np.hstack((image,gf))
cv2.imshow("res",res)
cv2.imwrite(r'/home/cheng/Documents/practice_py/cv/resface03.png.jpg', gf)
cv2.waitKey(0)


def costtime(func):
# time start
t1 = cv2.getTickCount()
func()
# time end
t2 = cv2.getTickCount()

# 计算执行秒数,利用getTickFrequency()获取时钟频率
t = (t2 - t1) / cv2.getTickFrequency()
print(t)



if __name__ == "__main__":
# costtime(gpu_run)
costtime(run)