OpenCV高斯平滑及图像增强的原理及实现方法

高斯平滑

假设一个列数为W,行数为H的高斯卷计算子gaussKernel,其中W,H均为奇数,描点位置在((H-1)/2 ,(W-1)/2),构建高斯卷积核的步骤如下
1.计算高斯矩阵:

\[gaussMatrix_(H*W) = [gauss(r,c,\sigma)] (0\leqslant r \leqslant H-1,0\leqslant c\leqslant W-1 ) \]

2.计算高斯矩阵的和:

\[sum(gaussMatrix_(H*W)) \]

3.高斯矩阵除以其本身的和,也就是归一化:

\[gaussKernel_(H*W) = gaussMatrix/sum(gaussMatrix) \]

下面利用Python来实现构建高斯卷积算子:

def getGaussKernel(sigma, H, W):
    r, c = np.mgrid[0:H:1, 0:W:1]
    r -= (H - 1) / 2
    c -= (W - 1) / 2
    gaussMatrix = np.exp(-0.5 * (np.power(r) + np.power(c)) / math.pow(sigma, 2))
    # 计算高斯矩阵的和
    sunGM = np.sum(gaussMatrix)
    # 归一化
    gaussKernel = gaussMatrix / sunGM
    return gaussKernel

高斯卷积核可以分离成一维水平方向上的高斯核和一维垂直方向上的高斯核,在OpenCV中给出了构建一维垂直方向上的高斯卷积核的函数:

Mat getGaussianKernel(int ksize, double sigma, in ktype = CV/_64F)

参数释意
ksize 一维垂直方向上的高斯核行数,正奇数
sigma 标准差
ktype 返回值的数据类型为CV_32F或CV_64F,默认是CV_64F

下面通过Python代码来具体的实现图像的高斯平滑,我们首先会对图像水平方向进行卷积,然后再对垂直方向进行卷积,其中sigma代表高斯卷积核的标准差

def gaussBlur(image,sigma,H,W,_boundary = 'fill', _fillvalue = 0):
    #水平方向上的高斯卷积核
    gaussKenrnel_x = cv2.getGaussianKernel(sigma,W,cv2.CV_64F)
    #进行转置
    gaussKenrnel_x = np.transpose(gaussKenrnel_x)
    #图像矩阵与水平高斯核卷积
    gaussBlur_x = signal.convolve2d(image,gaussKenrnel_x,mode='same',boundary=_boundary,fillvalue=_fillvalue)
    #构建垂直方向上的卷积核
    gaussKenrnel_y = cv2.getGaussianKernel(sigma,H,cv2.CV_64F)
    #图像与垂直方向上的高斯核卷积核
    gaussBlur_xy = signal.convolve2d(gaussBlur_x,gaussKenrnel_y,mode='same',boundary= _boundary,fillvalue=_fillvalue)
    return gaussBlur_xy
if __name__ == "__main__":
    image = cv2.imread("../images/timg.jpg", cv2.IMREAD_GRAYSCALE)
    cv2.imshow("image",image)
    #高斯平滑
    blurImage = gaussBlur(image, 5, 400, 400, 'symm')
    #对bIurImage进行灰度级显示
    blurImage = np.round(blurImage)
    blurImage = blurImage.astype(np.uint8)
    cv2.imshow("GaussBlur", blurImage)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

图像增强

为了得到更加清晰的图像我们需要通过技术对图像进行处理,比如使用对比度增强的方法来处理图像,对比度增强就是对图像输出的灰度级放大到指定的程度,获得图像质量的提升。本文主要通过代码的方式,通过OpenCV的内置函数将图像处理到我们理想的结果。

灰度直方图:

灰度直方图通过描述灰度级在图像矩阵中的像素个数来展示图像灰度级的信息,通过灰度直方图的统计我们可以看到每个灰度值的占有率。下面是一个灰度直方图的实现:

import cv2
import numpy as np
import sys
import matplotlib.pyplot as plt

#计算灰度直方图
def calcGrayHist(image):
    rows,clos = image.shape
    #创建一个矩阵用于存储灰度值
    grahHist = np.zeros([256],np.uint64)
    print('这是初始化矩阵')
    print(grahHist )
    for r in range(rows):
        for c in range(clos):
            #通过图像矩阵的遍历来将灰度值信息放入我们定义的矩阵中
            grahHist[image[r][c]] +=1
    print('这是赋值后的矩阵')
    print(grahHist)
    return grahHist
if __name__=="__main__":
    image = cv2.imread("../img/aa.jpg",cv2.IMREAD_GRAYSCALE)
    grahHist = calcGrayHist(image)
    x_range = range(256)
    plt.plot(x_range,grahHist,'-',linewidth= 3,c='k')
    #设置坐标轴的范围
    y_maxValue = np.max(grahHist)
    plt.axis([0,255,0,y_maxValue])
    #设置标签
    plt.xlabel('gray Level')
    plt.ylabel("number of pixels")
    #显示灰度直方图
    plt.show()

运行结果

线性变换:

图像的线性变换无疑就是利用矩阵的乘法就行线性变换,比如一个矩阵I ,2I,3I (np.unt8 ndarry类型就是unt8类型)就是一个矩阵的变换.

import cv2
import numpy as np
import sys

if __name__=="__main__":
    img = cv2.imread("../img/ae.jpg",cv2.IMREAD_GRAYSCALE)
    a=2
    #线性变换  定义float类型
    O = float(a)*img
    #数据截取  如果大于255 取 255
    O[0>255] = 255
    #数据类型的转换
    O = np.round(O)
    O = O.astype(np.uint8)
    cv2.imshow("img",img)
    cv2.imshow('enhance',O)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

直方图正规化:

import cv2
import numpy as np
import sys
from enhance.GrayHist import mget
if __name__=="__main__":
    img = cv2.imread("../img/o3.jpg",cv2.IMREAD_GRAYSCALE)
    #求出img 的最大最小值
    Maximg = np.max(img)
    Minimg = np.min(img)
    print(Maximg, Minimg, '-----------')
    #输出最小灰度级和最大灰度级
    Omin,Omax = 0,255
    #求 a, b
    a = float(Omax - Omin)/(Maximg - Minimg)
    b = Omin - a*Minimg
    print(a,b,'-----------')
    #线性变换
    O = a*img + b
    O = O.astype(np.uint8)
    #利用灰度直方图进行比较  mget为GrayHist中的写方法
    mget(img)
    mget(O)


    cv2.imshow('img',img)
    cv2.imshow('enhance',O)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

伽玛变换:

将一张图的灰度值归至[0,1]后,对于8位图来说,除以255即可。伽玛变换就是令O(r,c)=I(r,c)γI(r,c)γ,0r<H,0≤r<H,0≤c<W.
γγ等于1时图像不发生变换,而当γγ大于0且小于1时就可以增强图像的对比度,相反的当γγ大于1时就可以使图像对比度降低。 以下是伽玛变换在OpenCV中的实现:

import cv2
import numpy as np
import sys

# 伽玛变换  power函数实现幂函数

if __name__ == "__main__":
    img = cv2.imread("../img/ae.jpg", cv2.IMREAD_GRAYSCALE)
    # 归1
    Cimg = img / 255
    # 伽玛变换
    gamma = 0.5
    O = np.power(Cimg,gamma)
    #效果
    cv2.imshow('img',img)
    cv2.imshow('O',O)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

直方图均衡化:

  • 计算图像的灰度直方图
  • 计算灰度直方图的累加直方图
  • 根据累加的直方图和直方图均衡化的原理得到输入灰度级与输出灰度级之间的映射关系
  • 使用循环的方式得到输出图像的每一个像素的灰度级
    import cv2
    import numpy as np
    from enhance.GrayHist import calcGrayHist
    
    #直方图的均衡化
    if __name__ == "__main__":
        image = cv2.imread("../img/ae.jpg", cv2.IMREAD_GRAYSCALE)
        rows,cols = image.shape
        #计算灰度直方图
        grayHist = calcGrayHist(image)
        #计算累加灰度直方图
        zeroCumuMoment = np.zeros([256], np.uint32)
        for p in range(256):
            if p == 0:
                zeroCumuMoment[p] = grayHist[0]
            else:
                zeroCumuMoment[p] = zeroCumuMoment[p-1] + grayHist[p]
        #根据累加的灰度直方图得到输入与输出灰度级之间的映射关系
        output = np.zeros([256],np.uint8)
        cofficient = 256.0/(rows*cols)
        for p in range(256):
            q = cofficient * float(zeroCumuMoment[p])-1
            if q >=0:
                output[p] = np.math.floor(q)
            else:
                output[p] = 0
        #得出均衡化图像
        equalHistimg = np.zeros(image.shape,np.uint8)
        for r in range(rows):
            for c in range(cols):
                equalHistimg[r][c] = output[image[r][c]]
        cv2.imshow('image',image)
        cv2.imshow('histimage',equalHistimg)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

     

posted @ 2022-04-15 20:49  葵葵的执着  阅读(699)  评论(0编辑  收藏  举报