介绍:横坐标是灰度值(就是矩阵中存的数值),纵坐标是出现次数,也可以对数值进行归一化处理,使频数之和为1
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()#显示
就是对各点进行线性运算实现对比度变化,也可以对不同区域进行不同变换
注意一下超出范围的处理,比如类型为uint8时,大于255,要转化为float,再截断(比如截成255),再转换回去
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]
这个方法适合于那些直方图扭成一团,而且聚在两端的图的对比度调整
也可以分区域进行线性变化
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)
这个,如果imshow输出的图像是浮点数则认为已进行归一化,所以之前显示白色就是因为它默认是归一化的,但事实上我没有,于是全白
然后这个opencv中给了现成的函数:
一般用NORM_MINMAX模式就行了,这也就是我们之前讲的那个,感觉这个最精确
原理:
最后一句话:归一化后都在0到1中,伽马小于1算完后会变大(也就变亮了),伽马大于1也是同样的分析思路
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()
这个滑条真的很方便。
感觉这个是最普适的
强调一点,就是这个方法变化后的直方图肯定不是平的,这只是提供了不同频度的灰度值调整的过程,相当于一根根柱子的移动,移到哪由计算得到。
感受一下:
# -*- 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()
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)