• 图像增强之灰度变换和直方图均衡化(附代码python+opencv)


    一、图像增强的概念和分类

    概念:图像增强是采用一系列技术去改善图像的视觉效果,或将图像转换成一种更适合于人或机器进行分析和处理的形式。例如采用一系列技术有选择地突出某些感兴趣的信息,同时抑制一些不需要的信息,提高图像的使用价值。
    分类:图像增强方法由增强的作用域出发,可分为空间域增强和频率域增强两种。
    空间域增强是直接对图像的各像素进行处理;
    频率域增强是对图像进行傅里叶变换后的频谱成分进行处理,然后逆傅里叶变换获得所需的图像。

    1. 空间域增强
      点运算:灰度变换、直方图修正(均衡化和规定化)
      局部运算:图像平滑、图像锐化

    2. 频率域增强
      高通滤波、低通滤波、同态滤波

    二、灰度变换

    • 灰度变换和二值化的区别:
    • 灰度变换是调整调整图像的灰度动态范围或图像对比度
    • 二值化是将图像的每个像素点调至0或255,只呈现白色或黑色

    二值化的代码:方法一:固定阈值二值化

    # function:将灰度图片转为二值化图片,方法一:固定阈值二值化
    import cv2 as cv
    
    gray_img = cv.imread('./img/gray_img.png')
    
    # 二值化函数
    ret, erzhihua_img = cv.threshold(gray_img, 100, 255, cv.THRESH_BINARY)
    
    cv.imshow('erzhihua_img', erzhihua_img)
    cv.imwrite('./img/erzhihua_img.png', erzhihua_img)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    方法二:算术平均的自适应二值化

    # function:算术平均的自适应二值化
    import cv2 as cv
    
    # 这里很奇怪,不能直接传灰度图片的imread路径,要直接是灰度图片,像下面这样
    img = cv.imread('./img/img.png')
    gray_img = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
    
    # 二值化函数
    erzhihua_img = cv.adaptiveThreshold(gray_img, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 11, 2)
    
    cv.imshow('erzhihua_img', erzhihua_img)
    cv.imwrite('./img/erzhihua1_img.png', erzhihua_img)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    方法三:高斯加权均值法自适应二值化

    # function:高斯加权均值法自适应二值化
    import cv2 as cv
    
    # 这里很奇怪,不能直接传灰度图片的imread路径,要直接是灰度图片,像下面这样
    img = cv.imread('./img/img.png')
    gray_img = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
    
    # 二值化函数
    erzhihua_img = cv.adaptiveThreshold(gray_img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 11, 8)
    
    cv.imshow('erzhihua_img', erzhihua_img)
    cv.imwrite('./img/erzhihua2_img.png', erzhihua_img)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    灰度变换通俗理解为将直方图的动态范围从小变大。

    在这里插入图片描述
    简单的将图像变灰:方法一

    import cv2 as cv
    
    img = cv.imread('./img/img.png')
    cv.imshow('rgb_img', img)
    
    gray_img = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
    cv.imshow('gray_img', gray_img)
    
    cv.imwrite('./img/gray_img.png', gray_img)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    方法2:

    import cv2 as cv
    
    gray1_img = cv.imread('./img/img.png', 0)
    
    cv.imshow('gray1_img', gray1_img)
    
    cv.imwrite('./img/gray1_img.png', gray1_img)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    1、线性变换

    将a ~ b映射到a’ ~ b’,当ab比a’b’小的时候,做的是灰度的拉伸,将图像变得更清晰,对比度越大,下图斜线的斜率是>1。

    在这里插入图片描述

    2、分段线性变换

    拉伸感兴趣的灰度区间。

    在这里插入图片描述

    3、非线性变换

    在这里插入图片描述
    对数变换代码:

    import cv2 as cv
    import copy
    import math
    
    # 读入原始图像
    img = cv.imread('./img/img.png', 1)
    
    # 灰度化处理:此灰度化处理用于图像二值化
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    # 对数变换
    logc = copy.deepcopy(gray)
    rows = img.shape[0]
    cols = img.shape[1]
    for i in range(rows):
        for j in range(cols):
            logc[i][j] = 10 * math.log(1 + logc[i][j])
    
    # 通过窗口展示图片 第一个参数为窗口名 第二个为读取的图片变量
    
    cv.imshow('logc', logc)
    cv.imwrite('./img/logc_img.png', logc)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    4、伽马变换

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • 代码中的系数为gamma的倒数,一般为2.2

    gamma变换代码1:

    import cv2 as cv
    import numpy as np
    
    
    # gamma correction
    def gamma_correction(img, c=1, g=2.5):
        out = img.copy()
        out /= 255.
        out = (1 / c * out) ** (1 / g)
        out *= 255
        out = out.astype(np.uint8)
        return out
    
    
    # Read image
    img = cv.imread('./img/img.png').astype(np.float)
    
    # Gammma correction
    out = gamma_correction(img)
    
    # Save result
    cv.imshow("result", out)
    cv.imwrite("./img/gamma1.jpg", out)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述
    gamma变换代码2:

    import cv2 as cv
    import copy
    
    # 读入原始图像
    img = cv.imread('./img/img.png', 1)
    
    # 伽马变换
    gamma = copy.deepcopy(img)
    rows = img.shape[0]
    cols = img.shape[1]
    for i in range(rows):
        for j in range(cols):
            gamma[i][j] = 3 * pow(gamma[i][j], 0.5)
    
    cv.imshow('gamma', gamma)
    cv.imwrite("./img/gamma2.jpg", gamma)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    三、直方图均衡化

    在这里插入图片描述
    在这里插入图片描述

    计算过程:Sk计到Sk并需要离散化一下(近似),就把原图当中的0~7对应过来了(注意不一定是一一对应)

    在这里插入图片描述
    结果:近似的
    在这里插入图片描述
    均衡化的图像:
    在这里插入图片描述
    直方图均衡化代码:(最普通的均衡化)

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('./img/img.png', 0)
    # flatten() 将数组变成一维
    hist, bins = np.histogram(img.flatten(), 255, [0, 255])
    # 计算累积分布图
    cdf = hist.cumsum()
    cdf_normalized = cdf * hist.max() / cdf.max()
    # 作图
    plt.figure(figsize=(14, 14), dpi=100)
    plt.subplot(1, 2, 1)
    plt.plot(cdf_normalized, color='b')
    plt.hist(img.flatten(), 255, [0, 255], color='r')
    plt.xlim([0, 255])
    plt.title('before')
    plt.legend(('cdf', 'histogram'), loc='upper left')
    # plt.show()
    
    equ = cv2.equalizeHist(img)  # 该函数的输入只能是灰度图,equalizeHist只能显示单通道函数
    res = np.hstack((img, equ))
    
    # 计算均衡化后的直方图
    hist1, bins1 = np.histogram(res.flatten(), 255, [0, 255])
    cdf1 = hist1.cumsum()
    cdf1_normalized = cdf1 * hist1.max() / cdf1.max()
    
    plt.subplot(1, 2, 2)
    plt.plot(cdf1_normalized, color='b')
    plt.hist(res.flatten(), 255, [0, 255], color='r')
    plt.xlim([0, 255])
    plt.legend(('cdf', 'histogram'), loc='upper left')
    plt.title('after')
    plt.savefig('./img/zhifangtu.png')
    plt.show()
    
    # stacking images side-by-side
    cv2.imshow('img', res)
    cv2.imwrite('./img/zhifangtu_img.png', res)
    cv2.waitKey()
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    直方图对比:
    在这里插入图片描述
    结果对比:
    在这里插入图片描述
    CLAHE 有限对比适应性直方图均衡化(自适应直方图均衡化):将直方图分成一小块一小块的,每一块进行直方图均衡化:
    代码:

    # function:CLAHE直方图均衡化
    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    img = cv2.imread('./img/img.png', 0)
    
    # flatten() 将数组变成一维
    hist, bins = np.histogram(img.flatten(), 255, [0, 255])
    # 计算累积分布图
    cdf = hist.cumsum()
    cdf_normalized = cdf * hist.max() / cdf.max()
    # 作图
    plt.figure(figsize=(14, 14), dpi=100)
    plt.subplot(1, 2, 1)
    plt.plot(cdf_normalized, color='b')
    plt.hist(img.flatten(), 255, [0, 255], color='r')
    plt.xlim([0, 255])
    plt.title('before')
    plt.legend(('cdf', 'histogram'), loc='upper left')
    
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    cl1 = clahe.apply(img)
    
    # 计算均衡化后的直方图
    hist1, bins1 = np.histogram(cl1.flatten(), 255, [0, 255])
    cdf1 = hist1.cumsum()
    cdf1_normalized = cdf1 * hist1.max() / cdf1.max()
    
    plt.subplot(1, 2, 2)
    plt.plot(cdf1_normalized, color='b')
    plt.hist(cl1.flatten(), 255, [0, 255], color='r')
    plt.xlim([0, 255])
    plt.legend(('cdf', 'histogram'), loc='upper left')
    plt.title('after')
    plt.savefig('./img/clahe.png')
    plt.show()
    
    cv2.imwrite('./img/clahe_1.jpg', cl1)
    cv2.waitKey()
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    直方图对比:
    在这里插入图片描述
    结果对比:
    在这里插入图片描述
    彩色图片的均衡化:先进行通道数分解,再合成
    代码:

    # 彩色图像均衡化
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    img = cv2.imread('./img/img.png', 1)
    
    # 原图像直方图
    # flatten() 将数组变成一维
    hist, bins = np.histogram(img.flatten(), 255, [0, 255])
    # 计算累积分布图
    cdf = hist.cumsum()
    cdf_normalized = cdf * hist.max() / cdf.max()
    # 作图
    plt.figure(figsize=(14, 14), dpi=100)
    plt.subplot(1, 2, 1)
    plt.plot(cdf_normalized, color='b')
    plt.hist(img.flatten(), 255, [0, 255], color='r')
    plt.xlim([0, 255])
    plt.title('before')
    plt.legend(('cdf', 'histogram'), loc='upper left')
    
    (b, g, r) = cv2.split(img)  # 通道分解
    bH = cv2.equalizeHist(b)
    gH = cv2.equalizeHist(g)
    rH = cv2.equalizeHist(r)
    result = cv2.merge((bH, gH, rH), )  # 通道合成
    res = np.hstack((img, result))
    
    # 计算均衡化后的直方图
    hist1, bins1 = np.histogram(res.flatten(), 255, [0, 255])
    cdf1 = hist1.cumsum()
    cdf1_normalized = cdf1 * hist1.max() / cdf1.max()
    
    plt.subplot(1, 2, 2)
    plt.plot(cdf1_normalized, color='b')
    plt.hist(res.flatten(), 255, [0, 255], color='r')
    plt.xlim([0, 255])
    plt.legend(('cdf', 'histogram'), loc='upper left')
    plt.title('after')
    plt.savefig('./img/zhifangtu_rgb_1.png')
    plt.show()
    
    cv2.imshow('dst', res)
    cv2.imwrite('./img/zhifangtu_rgb.png', res)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    直方图对比:
    在这里插入图片描述
    结果对比:
    在这里插入图片描述

  • 相关阅读:
    解决gpedit.msc命令无法打开的问题
    tomcat 把webappp设置在其他目录
    迁移Linux服务器用户数据(将一个服务器的Linux用户数据迁移到另一个Linux服务器用户的流程)
    【面试:并发篇32:cas】原子类型
    Web渗透_手动漏洞挖掘
    来自北大算法课的Leetcode题解:7. 整数反转
    后端框架有哪些
    create_generated_clock invert preinvert shift_edge是否符合设计真实状态很重要【示例1】
    Mysql函数
    Flask框架参数类型以及获取方法
  • 原文地址:https://blog.csdn.net/weixin_45703331/article/details/127849282