opencv python 高斯滤波_Python OpenCV实验(3):实现图像的高斯滤波处理

实验要求:

1)通过调整高斯函数的标准差(sigma)来控制平滑程度;

给定函数:void Gaussian(const MyImage &input, MyImage &output, double sigma);

2)滤波窗口大小取为[6sigma-1]/22+1,[.]表示取整;

3)利用二维高斯函数的行列可分离性进行加速;

先对每行进行一维

实验思路:

1.二维高斯滤波器的生成:模板的中心点是(center, center),根据G(x, y)高斯公式,其他点(i, j)有x = i – center; y = center – j 代入计算。这样求到了模板上每个位置的值,现在是小数。我们可以将模板左上角的像素值 v 乘以 1/v,这样左上角的元素就变为了1。模板的其他元素w也都乘以 1/v即int(w/v),这样所有元素都变为了整数。归一化时除以模板所有元素和就行。

2.一维高斯滤波器的生成也几乎是一样的。行列分离就是用一维高斯滤波器先对行操作,再对列操作,反过来也是一样的。

实验效果:

实验代码:

整个实验代码中包含两个函数Gaussian(未实现行列分离)和SeperateGaussian(实现了行列分离)。

采用行列分离一定要充分利用numpy的特性,否则可能会导致速度下降。以sigma等于1.03为例,Gaussian大约为6.26秒,SeperateGaussian如果仍是逐行逐列去遍历,时间是11秒左右,竟然比未行列分离慢,这显然是不可接受的。通过使用numpy的矩阵乘法,时间下降至0.07秒,如果将k也放入矩阵进行运算时间增加了0.015秒左右,即0.085秒左右。

import cv2 as cv

import numpy as np

def Gaussian(inputImage, outputImage, sigma):

timeBegin = cv.getTickCount()

# 产生二维高斯滤波器kernel,行列不分离

size = int(int(6*sigma-1)//2*2+1) # 高斯滤波器大小为:size x size,size为奇数

kernel = np.zeros([size, size], dtype=np.int)

center = size//2 # 将滤波器分为size x size个小方格,中心点为center,坐标为(0, 0)

normal = 1/(np.exp(-(2*center*center)/(2*(sigma*sigma)))) # 用于整数化

sumAll = 0 # 模板参数总和

for i in range(size):

for j in range(size):

x = i-center # 方格的横坐标

y = center-j # 方格的纵坐标

kernel[i, j] = int(np.exp(-(x*x+y*y)/(2*sigma*sigma)) * normal)

sumAll += kernel[i, j]

# print(kernel[i, j], end=' ') # 打印模板,与下一行共同使用

# print('') # 打印模板,与上一行共同使用

# 对图像inputImage增添

border = center # 需要添加的边界大小

transImage = cv.copyMakeBorder(inputImage, border, border, border, border,

borderType=cv.BORDER_REPLICATE) # 复制最边缘像素

# 开始平滑操作

rows, cols, channels = inputImage.shape

for i in range(rows):

for j in range(cols):

for k in range(channels):

temp = np.sum(np.multiply(transImage[i:i+size, j:j+size, k], kernel)) // sumAll

if temp < 0:

temp = 0

elif temp > 255:

temp = 255

outputImage[i, j, k] = temp

timeEnd = cv.getTickCount()

time = (timeEnd-timeBegin)/cv.getTickFrequency()

return time

def SeperateGaussian(inputImage, outputImage, sigma):

timeBegin = cv.getTickCount()

# 产生一维高斯滤波器kernel,行列分离

size = int(int(6*sigma-1)//2*2+1) # 高斯滤波器大小为:size x size,size为奇数

kernel = np.zeros([size], dtype=np.int)

center = size//2 # 将滤波器分为size x size个小方格,中心点为center,坐标为(0, 0)

normal = 1/(np.exp(-center*center/(2*(sigma*sigma)))) # 用于整数化

sumAll = 0 # 模板参数总和

for i in range(size):

kernel[i] = int(np.exp(-(i-center)*(i-center)/(2*sigma*sigma)) * normal)

sumAll += kernel[i]

#print(kernel[i], end=' ') # 打印模板

kernelRow = kernel

kernelCol = np.resize(kernel, (size, 1))

#print(kernelCol)

# 对图像inputImage增添

border = center # 需要添加的边界大小

transImage = cv.copyMakeBorder(inputImage, border, border, border, border,

borderType=cv.BORDER_REPLICATE) # 复制最边缘像素

# 开始平滑操作

rows, cols, channels = inputImage.shape

# 对行操作

for j in range(cols):

for k in range(channels):

temp = np.sum(np.multiply(transImage[:, j:j+size, k], kernelRow), axis=1) // sumAll

transImage[:, j+border, k] = temp

# 对列操作

for i in range(rows):

for k in range(channels):

temp = np.sum(np.multiply(transImage[i:i + size, border:cols + border, k], kernelCol), axis=0) // sumAll

outputImage[i, :, k] = temp

timeEnd = cv.getTickCount()

time = (timeEnd - timeBegin) / cv.getTickFrequency()

return time

sig = float(input('Please input the value of sigma: '))

print('Please choose the mode of Gaussian: ')

print(' Type 1 if you want to Gaussian')

print(' Type 2 if you want to SeperateGaussian')

print(' Type 3 if yuu want to both')

flag = int(input('The mode is: '))

imgSrc = cv.imread('../images/images2_1/a.jpg') # (481, 641, 3)

imgDst = np.zeros(list(imgSrc.shape), dtype='uint8')

time1 = 0 # 行列不分离的时间

time2 = 0 # 行列分离的时间

time = 0 # 两种方式的时间差

#print(imgSrc.shape)

if flag == 1:

time = Gaussian(imgSrc, imgDst, sig)

elif flag == 2:

time = SeperateGaussian(imgSrc, imgDst, sig)

elif flag == 3:

time1 = Gaussian(imgSrc, imgDst, sig)

time2 = SeperateGaussian(imgSrc, imgDst, sig)

strSigma = 'Gaussian image(sigma: ' + str(sig) + ')'

cv.imshow('source image', imgSrc)

cv.imshow(strSigma, imgDst)

saveSigma = str(sig) + '.png'

cv.imwrite(saveSigma, imgDst)

print("Successful!!!")

if flag == 1 or flag == 2:

print('time(s):', time)

elif flag == 3:

print('time1(s):', time1)

print('time2(s):', time2)

print('time2-time1 =', time2-time1)

cv.waitKey(0)

cv.destroyAllWindows()

你可能感兴趣的:(opencv,python,高斯滤波)