import numpy as np
import cv2
import matplotlib.pyplot as plt
#定义calcGrayHist函数来计算每个灰度级的出现的次数
def calcGrayHist(image):
# 灰度图像的高、宽
rows, cols = image.shape
# 存储灰度直方图
grayHist = np.zeros([256], np.uint64) #图像的灰度级范围是0~255
for r in range(rows):
for c in range(cols):
grayHist[image[r][c]] +=1
return grayHist
if __name__ == "__main__":
img = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
#计算灰度直方图
grayHist = calcGrayHist(img)
#画出直方图
x_range = range(256)
plt.plot(x_range, grayHist, 'r', linewidth=2, c='orange')
#设置坐标轴的范围
y_maxValue = np.max(grayHist)
plt.axis([0, 255, 0, y_maxValue]) #画图范围
plt.xlabel("gray Level")
plt.ylabel("number of pixels")
plt.show()
from matplotlib import pyplot as plt
import cv2
img = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap=plt.cm.gray)
#images,必须用方括号括起来,一维数组
#channels,是用于计算直方图的通道,这里使用灰度图计算直方图,所以就直接使用第一个通道。
#Mask,图像掩模,没有使用则填写None。
#histSize,表示这个直方图分成多少份(即多少个直方柱)。
#ranges,表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
#accumulate,为一个布尔值,用来表示直方图是否叠加。
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("gray Level")
plt.ylabel("number of pixels")
plt.plot(hist)
plt.xlim([0, 256])
plt.show()
类似于灰度直方图处理
from matplotlib import pyplot as plt
import cv2
img = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_ANYCOLOR)
chans = cv2.split(img)
colors = ('b', 'g', 'r')
plt.figure()
plt.title("Color Histogram")
plt.xlabel("gray Level")
plt.ylabel("number of pixels")
for (chan, color) in zip(chans, colors):
hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
plt.plot(hist, color = color) # 赋予各自颜色
plt.xlim([0, 256]) # 设置当前x轴
plt.show()
假设输入图像为 I I I,将最小灰度级记为 I m i n I_{min} Imin,最大灰度级记为 I m a x I_{max} Imax。
输出图像为 O O O,灰度级范围为 [ O m i n , O m a x ] [O_{min},O_{max}] [Omin,Omax],则
O = I − I m i n I m a x − I m i n ( O m a x − O m i n ) + O m i n O=\frac{I-I_{min}}{I_{max}-I_{min}}(O_{max}-O_{min})+O_{min} O=Imax−IminI−Imin(Omax−Omin)+Omin
一般令 O m a x = 255 O_{max}=255 Omax=255, O m i n = 0 O_{min}=0 Omin=0.
cv2.normalize(src, dst, alpha, beta, norm_type, dtype, mask)
详细
:
src-输入数组
dst-输出数组,支持原地运算
alpha-range normalization模式的最小值
beta-range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
normType-归一化的类型,可以有以下的取值:
1. NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
2. NORM_INF: 此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)
3.NORM_L1 : 归一化数组的L1-范数(绝对值的和)
4.NORM_L2: 归一化数组的(欧几里德)L2-范数
dtype-dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).
mask-操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。
适用于:灰度级主要在0 ~ 150之间,造成图像对比度较低,可用直方图归一化将图像灰度级拉伸到0~255,使其更清晰。
#直方图正规化API
#灰度级主要在0~150之间,造成图像对比度较低,可用直方图正规化将图像灰度级拉伸到0~255,使其更清晰
import cv2
import numpy as np
import matplotlib.pyplot as plt
#灰度图像转化为ndarray类型
if __name__ == "__main__":
src = cv2.imread(r'C:\Users\h\Desktop\image\low.jpg', cv2.IMREAD_ANYCOLOR)
# dst = np.zeros_like(src)
cv2.normalize(src, dst,0, 255, cv2.NORM_MINMAX, cv2.CV_8U) #公式
cv2.imshow("src", src)
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
#计算灰度直方图
grayHist = cv2.calcHist([src], [0], None, [256], [0, 256])
grayHist1 = cv2.calcHist([dst], [0], None, [256], [0, 256])
#画出直方图
x_range = range(256)
plt.plot(x_range, grayHist, 'r', linewidth=1.5, c='black')
plt.plot(x_range, grayHist1, 'r', linewidth=1.5, c='b')
#设置坐标轴的范围
y_maxValue = np.max(grayHist)
plt.axis([0, 255, 0, y_maxValue]) #画图范围
plt.xlabel("gray Level")
plt.ylabel("number of pixels")
plt.show()
normalize可以处理多通道矩阵,即彩色图片可以增强
伽马变换(非线性变换)实际上就是对矩阵的每个值进行幂运算
O ( r , c ) = I ( r , c ) γ , 0 ≤ r < H , 0 ≤ c < W O(r,c)=I(r,c)^\gamma ,0\leq r<H,0\leq c<W O(r,c)=I(r,c)γ,0≤r<H,0≤c<W
适用于:灰度值主要集中在灰度直方图两侧,即灰度值较低和较高的范围内,可用伽马变换修正
import cv2
import numpy as np
#灰度图像转化为ndarray类型
I = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_ANYCOLOR)
#图像归一化
fI = I/255.0
#伽马变化
gamma = 0.4
O = np.power(fI, gamma)
#显示伽马变化后的结果
cv2.namedWindow("I", cv2.WINDOW_NORMAL)
cv2.namedWindow("O", cv2.WINDOW_NORMAL)
cv2.imshow("I", I)
cv2.imshow("O", O)
cv2.waitKey(0)
cv2.destroyAllWindows()
假设输入图像为 I I I,宽为 W W W,高为 H H H,输出图像为 O O O,图像的线性变换为:
O ( r , c ) = a ∗ I ( r , c ) + b , 0 ≤ r < H , 0 ≤ c < W O(r,c)=a*I(r,c)+b, 0\leq r<H, 0\leq c<W O(r,c)=a∗I(r,c)+b,0≤r<H,0≤c<W
拉伸图像,提升对比度
压缩图像,降低对比度
import cv2
import numpy as np
img = cv2.imread(r'C:\Users\x\Desktop\OpenCV-Pic\4\img4.jpg', cv2.IMREAD_GRAYSCALE)#GRAYSCALE
#线性变换
a = 2
O = float(a) * img
O[O>255] = 255 #大于255要截断为255
#数据类型的转换
O = np.round(O)
O = O.astype(np.uint8)
#显示原图与变换后的图的效果
cv2.imshow("img", img)
cv2.imshow("O", O)
cv2.waitKey(0)
cv2.destroyAllWindows()
在出现过于高的对比度时(超出预设好的"限制对比度",超出的部分会被裁剪,然后均匀分配到其他区域,这样就重构了直方图。
#限制对比度的自适应直方图均衡化
import cv2
src = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
#创建CLAHE对象 clipLimit限制对比度,tileGridSize块的大小
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
#限制对比度的自适应阈值
dst = clahe.apply(src)
cv2.imshow("src", src)
cv2.imshow("clahe",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
节选:
原文:https://blog.csdn.net/qq_40755643/article/details/84032773
对比度的拉伸受图像噪声的影响会很明显,在去除噪声后再使用对比度增强效果会更好