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()
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值