对比度增强

灰度直方图

介绍:横坐标是灰度值(就是矩阵中存的数值),纵坐标是出现次数,也可以对数值进行归一化处理,使频数之和为1

图像增强对比度拉伸 增强对比度在哪_opencv

python实现:

import cv2 as cv
import numpy as np
def countHist(image):
    rows,cols=image.shape#image通道数要求为1
    hist=np.ones([256],dtype=np.uint8)
    for i in range(rows):
        for j in range(cols):
            hist[image[i][j]]+=1#对各个灰度值计数
    return hist
src=cv.imread(r'C:\Users\19583\Desktop\3.png',cv.IMREAD_GRAYSCALE)
countHist(src)

直方图可视化显示

有助于判断选择哪个调整对比度方法

import cv2 as cv
import numpy as np
def countHist(image):
    rows,cols=image.shape#image通道数要求为1
    hist=np.ones([256],dtype=np.uint8)
    for i in range(rows):
        for j in range(cols):
            hist[image[i][j]]+=1#对各个灰度值计数
    return hist
src=cv.imread(r'C:\Users\19583\Desktop\3.png',cv.IMREAD_GRAYSCALE)
a=countHist(src)
import matplotlib.pyplot as plt
x=range(256)
plt.plot(x,a,'r',c='black')#x个数,矩阵(直方图),‘r’(不知道干什么),c=颜色(可以不写)
plt.axis([0,255,0,np.max(a)])#设置坐标轴范围
plt.xlabel('grayhist')#设置坐标名称
plt.ylabel('pinshu')
plt.show()#显示

图像增强对比度拉伸 增强对比度在哪_opencv_02

线性变化:

图像增强对比度拉伸 增强对比度在哪_opencv_03


就是对各点进行线性运算实现对比度变化,也可以对不同区域进行不同变换

注意一下超出范围的处理,比如类型为uint8时,大于255,要转化为float,再截断(比如截成255),再转换回去

python

I=np.array([233,200,12],dtype=np.uint8)
O=I*2.0#转化为double防止python的取mod处理
O[O>255]=255#进行截断
O=np.round(O)
O=O.astype(np.uint8)
print(I)
print(O)

[233 200 12]
[255 255 24]

这个方法适合于那些直方图扭成一团,而且聚在两端的图的对比度调整

图像增强对比度拉伸 增强对比度在哪_直方图均衡化_04


也可以分区域进行线性变化

图像增强对比度拉伸 增强对比度在哪_灰度直方图_05

直方图正规化

原理,比较简单直接上图:

图像增强对比度拉伸 增强对比度在哪_灰度直方图_06


归一,放大,平移

python实现

import numpy as np
import cv2
#直方图正规化
#1、若输入是 8 位图 ,一般设置 O_min = 0,O_max = 255
#2、若输入的是归一化的图像,一般设置 O_min = 0,O_max = 1
def histNormalized(InputImage,O_min = 0,O_max = 255):
    #得到输入图像的最小灰度值
    I_min = np.min(InputImage)
    #得到输入图像的最大灰度值
    I_max = np.max(InputImage)
    #得到输入图像的宽高
    rows,cols = InputImage.shape
    #输出图像
    OutputImage = np.zeros(InputImage.shape,np.float32)
    #输出图像的映射
    cofficient = float(O_max - O_min)/float(I_max - I_min)
    print(cofficient)
    for r in range(rows):
        for c in range(cols):
            OutputImage[r][c] = cofficient*( InputImage[r][c] - I_min) + O_min
    print(OutputImage)
    return OutputImage
image=cv2.imread(r'C:\Users\19583\Desktop\3.jpg',cv2.IMREAD_GRAYSCALE)
image=cv2.resize(image,(500,500))
gj1=histNormalized(image)/255#除了个255就正常了,不知道为什么,找到原因了,看下图
cv2.imshow('1',image)
cv2.imshow('2',gj1)
cv2.waitKey(0)

图像增强对比度拉伸 增强对比度在哪_图像增强对比度拉伸_07


图像增强对比度拉伸 增强对比度在哪_灰度直方图_08


这个,如果imshow输出的图像是浮点数则认为已进行归一化,所以之前显示白色就是因为它默认是归一化的,但事实上我没有,于是全白然后这个opencv中给了现成的函数:

图像增强对比度拉伸 增强对比度在哪_灰度直方图_09


图像增强对比度拉伸 增强对比度在哪_图像增强对比度拉伸_10


图像增强对比度拉伸 增强对比度在哪_灰度直方图_11


一般用NORM_MINMAX模式就行了,这也就是我们之前讲的那个,感觉这个最精确

伽马变化

原理:

图像增强对比度拉伸 增强对比度在哪_图像增强对比度拉伸_12


最后一句话:归一化后都在0到1中,伽马小于1算完后会变大(也就变亮了),伽马大于1也是同样的分析思路

图像增强对比度拉伸 增强对比度在哪_归一化_13

python实现

import cv2
import numpy as np
image=cv2.imread(r'C:\Users\19583\Desktop\3.jpg',cv2.IMREAD_GRAYSCALE)
image=cv2.resize(image,(500,500))
MAX_VALUE = 200
value = 40
segValue = float(value)
#伽马调整需要先将图像归一化
image_0_1 = image/255.0
#伽马调整后的图像显示窗口
cv2.namedWindow("gamma_contrast",cv2.WND_PROP_AUTOSIZE)
#调整 gamma 值,观察图像的变换
def callback_contrast(_value):
    gamma = float(_value)/segValue
    contrastImage = np.power(image_0_1,gamma)
    cv2.imshow("gamma_contrast",contrastImage)
    #保存伽马调整的结果
    contrastImage*=255#保存要乘255
    contrastImage = np.round(contrastImage)
    contrastImage = contrastImage.astype(np.uint8)
    cv2.imwrite("gamma.jpg",contrastImage)
callback_contrast(value)
cv2.createTrackbar("value","gamma_contrast",value,MAX_VALUE,callback_contrast)#前面两个不用管,后面是值(滑动可以改变),最大值(滑条的极限),滑完后调用的函数
cv2.waitKey(0)
cv2.destroyAllWindows()

图像增强对比度拉伸 增强对比度在哪_直方图均衡化_14


这个滑条真的很方便。

全局直方图均衡化

感觉这个是最普适的

图像增强对比度拉伸 增强对比度在哪_直方图均衡化_15


图像增强对比度拉伸 增强对比度在哪_灰度直方图_16


强调一点,就是这个方法变化后的直方图肯定不是平的,这只是提供了不同频度的灰度值调整的过程,相当于一根根柱子的移动,移到哪由计算得到。

感受一下:

图像增强对比度拉伸 增强对比度在哪_直方图均衡化_17

python实现:

# -*- coding: utf-8 -*-
import sys
import numpy as np
import cv2
import math
import matplotlib.pyplot as plt


# 计算图像灰度直方图
def calcGrayHist(image):
    # 灰度图像矩阵的宽高
    rows, cols = image.shape
    # 存储灰度直方图
    grayHist = np.zeros([256], np.uint32)
    for r in range(rows):
        for c in range(cols):
            grayHist[image[r][c]] += 1
    return grayHist


# 直方图均衡化
def equalHist(image):
    # 灰度图像矩阵的宽高
    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_q = 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_q[p] = math.floor(q)
        else:
            outPut_q[p] = 0
    # 得到直方图均衡化后的图像
    equalHistImage = np.zeros(image.shape, np.uint8)
    for r in range(rows):
        for c in range(cols):
            equalHistImage[r][c] = outPut_q[image[r][c]]
    return equalHistImage


# 主函数
if __name__ == "__main__":
    if len(sys.argv) > 1:
        image = cv2.imread(sys.argv[1], cv2.IMREAD_GRAYSCALE)
    else:
        print("Usge:python equalHist.py imageFile")
    # 显示原图像
    cv2.imshow("image", image)
    # 直方图均衡化
    result = equalHist(image)
    cv2.imshow("equalHist", result)
    cv2.imwrite("equalHist.jpg", result)
    # 直方图均衡话后的灰度直方图
    # 组数
    numberBins = 256
    # 计算灰度直方图
    rows, cols = image.shape
    histEqualResultSeq = result.reshape([rows * cols, ])
    histogram, bins, patch_image = plt.hist(histEqualResultSeq, numberBins, facecolor='black', histtype='bar')
    # 设置坐标轴的标签
    plt.xlabel(u"gray Level")
    plt.ylabel(u"number of pixels")
    # 设置坐标轴的范围
    y_maxValue = np.max(histogram)
    plt.axis([0, 255, 0, y_maxValue])
    plt.show()
    cv2.waitKey(0)
    cv2.destroyAllWindows()

图像增强对比度拉伸 增强对比度在哪_opencv_18

限制对比度的自适应直方图均衡化

图像增强对比度拉伸 增强对比度在哪_直方图均衡化_19


图像增强对比度拉伸 增强对比度在哪_归一化_20

python

src=cv2.imread(r'C:\Users\19583\Desktop\3.png',cv2.IMREAD_GRAYSCALE)
clahe=cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))#创建clahe对象
dst=clahe.apply(src)
cv2.imshow('1',src)
cv2.imshow('2',dst)
cv2.waitKey(0)

图像增强对比度拉伸 增强对比度在哪_图像增强对比度拉伸_21


这个与上一种方法相比不易受到噪点的影响