第七部分、图像操作-3
- 第一节、图像统计信息
- 1.像素值统计
- 2.函数支持说明
- 3.代码练习与测试
- 第二节、图像直方图
- 1.图像直方图定义
- 2.直方图函数
- 3.代码练习与测试
- 第三节、图像直方图均衡化
- 1.直方图均衡化
- 2.直方图均衡化函数
- 3.代码练习与测试
- 学习参考
第一节、图像统计信息
1.像素值统计
对单通道来说,一个像素点除了R,G,B三个维度之外,还有两个维度表示位置信息x,y,所以一个单通道的图片,每个像素点是五个维度。
对像素值进行统计与像素所处的位置无关只是单纯统计数值的大小。
(图像像素在OpenCV中相当于数组)
例如:
-
以单通道为例
- 均值
-
均值 + 方差
-
根据计算出来的均值和方差,可以对图像所携带的信息做出一些判断。
比如方差,方差就是数据的分散程度(偏离均值)。图像中有个人和有辆车,那么他们的灰度值是不同的(颜色不同),你把全图像的灰度值取平均,偏离平均值越大,方差越大。方差越大,说明信息越多,能量越大。 -
方差为0,说明该图片的像素点没有变化,是张纯色图片,说明图片不携带任何有效信息。
-
极值(最大、最小)
OpenCV中多通道计算均值方差,是在每个通道上分别计算的。
2.函数支持说明
1. cv.mean(src[, mask] ) ->retval
2. cv.meanStdDev(src[, mean[, stddev[, mask]]]) ->mean, stddev
3. cv.minMaxLoc(src[, mask]) ->minVal, maxVal, minLoc, maxLoc
# src表示输入图像,mask表示计算区域,不写mask表示计算全图
# mean, stddev, minVal, maxVal分别表示均值,标准方差,最小与最大
4. Dst = (Src-mean) * contrast + mean # 简单应用 -- 对比度
3.代码练习与测试
# 简单应用 -- 对比度
Dst = (Src-mean) * contrast + mean
# contrast < 1.0 降低对比度
# contrast > 1.0 提升对比度
# 例如,均值是70,100-70=30,当contrast=0.5时,差值变为30*0.5=15。
# 图像像素统计 -- 改变对比度 + 均值
def stats_demo_2():
image = cv.imread(r"F:\python\opencv-4.x\samples\data\butterfly.jpg")
cv.namedWindow("butterfly", cv.WINDOW_AUTOSIZE)
cv.imshow("butterfly", image)
# 计算全图均值
bgr_m = cv.mean(image)
# 对原图像设置低对比度
sub_m = np.float32(image)[:, :] - (bgr_m[0], bgr_m[1], bgr_m[2])
result = sub_m * 0.5 # 提升差值
result = result[:, :] + (bgr_m[0], bgr_m[1], bgr_m[2]) # 提升差值之后还要把均值加上去
cv.imshow("low-contrast-butterfly", cv.convertScaleAbs(result)) # convertScaleAbs转换为绝对值,然后转成CV_8UC
# 对原图像设置高对比度
result2 = sub_m * 2.0 # 提升差值
result2 = result2[:, :] + (bgr_m[0], bgr_m[1], bgr_m[2]) # 提升差值之后还要把均值加上去
cv.imshow("high-contrast-butterfly", cv.convertScaleAbs(result2)) # convertScaleAbs转换为绝对值,然后转成CV_8UC
# 输出不同对比度下的图片均值
m1 = cv.mean(image)
m2 = cv.mean(cv.convertScaleAbs(result))
m3 = cv.mean(cv.convertScaleAbs(result2))
print("image:", m1)
print("result_low:", m2)
print("result_high:", m3)
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:
上面三张图片的像素均值:可以看出均值可以反应出图片的明暗程度
# 图像像素统计 -- 均值、方差、极值(最大、最小)
def stats_demo_1():
# 计算均值和方差
roi = np.array([[5, 3, 4], [9, 6, 7], [8, 2, 3]], dtype=np.uint8) # 定义一个3*3的数组
mask = np.array([[0, 3, 0], [0, 6, 0], [0, 2, 0]], dtype=np.uint8) # 定义一个mask区域
m1 = cv.meanStdDev(roi) # 计算全图均值,方差
m2 = cv.meanStdDev(roi, mask=mask) # 计算mask区域的均值,方差
minx, maxx, minx_loc, max_loc = cv.minMaxLoc(roi) # 计算最小值,最大值,最小值坐标,最大值坐标
print("roi:\n", roi, "\n", "mask:\n", mask)
print("m1:", m1, "\n", "m2: ", m2)
print("min: ", minx, " max: ", maxx, " min_loc: ", minx_loc, " max_loc: ", max_loc)
# 计算均值
m3 = cv.mean(roi) # 计算全图均值
# 计算结果是四个值,对应四个通道,opencv使用mat(数组矩阵)来表示图片数据,其中四个通道分别表示R,G,B,透明度
m4 = cv.meanStdDev(roi, mask=mask) # 计算mask区域的均值和方差
print("roi:\n", roi, "\n", "mask:\n", mask)
print("m3: ", m3, "\n", "m4: ", m4)
结果示例:
第二节、图像直方图
1.图像直方图定义
图像直方图就是图像像素值的分布
例如,有图像数据8x8,像素值范围0~14共15个灰度等级,统计得到各个等级(x)出现次数(y)及直方图如右侧所示,每个紫色的长条叫BIN
每一个图像都可以绘制出自己的图像直方图
三个通道三个不同的直方图分布,将上图中的每个顶点连成线
注意:两个图像直方图相同,但是图像可能不同,因为直方图只关注了像素信息,没有关注空间位置信息。
2.直方图函数
1. calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) -> hist
# images表示图像
# channels表示通道
# mask 默认None
# histSzie表示bin的个数,横坐标的等级个数
# ranges表示通道的取值范围
# 例如 hist = cv.calcHist([image], [i], None, [32], [0, 255])
# image输入图像
# i表示通道索引
# mask=None
# 表示分为32个bin
# 表示取值范围0~256,即每个bin是256/32 = 每个范围的步长为8,即8个灰度等级
# hsv中h通道的取值范围为0-180,sv取值范围为0-255
3.代码练习与测试
# 图像直方图
def image_hist():
image = cv.imread(r"F:\python\opencv-4.x\samples\data\ml.png")
cv.imshow("input", image)
color = ('blue', 'green', 'red')
# enumerate遍历数组类型同时返回下标和对应数组值
for i, color in enumerate(color):
# 一共分32类,每一类256/32步长,按照B,G,R的通道顺序一次使用blue,green,red颜色绘制
hist = cv.calcHist([image], [i], None, [32], [0, 255])
print(hist.dtype)
plt.plot(hist, color=color)
plt.xlim([0, 32])
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:
第三节、图像直方图均衡化
1.直方图均衡化
均衡化作用:
- 提升对比度(通过拉大低值和高值之间的差距)
- 灰度图像支持
- k类别名
- rk每类对应的等级分数
- nk每类的像素点数
- nk/n占总像素的比例
- Sk表示累计(0.44 = 0.19+0.25)
- ps(sk)表示每一个s累计之后所属类的概率
三个通道三个不同的直方图分布
2.直方图均衡化函数
cv.equalizeHist(src[, dst]) --> dst
# src必须是八位(0,255)单通道图像(即必须是个灰度图像)
# dst返回结果图像,类型与src保持一致
3.代码练习与测试
# 图像直方图均衡化
def image_eq_demo():
# 直接读入灰度图片
# image = cv.imread(r"F:\python\opencv-4.x\samples\data\lena.jpg", cv.IMREAD_GRAYSCALE)
# 读入RGB彩色图片,切分通道,取单通道
image = cv.imread(r"F:\python\opencv-4.x\samples\data\lena.jpg")
image = cv.split(image)
cv.imshow("input", image[0])
# 提取原图的B通道作图像直方图
hist = cv.calcHist([image[0]], [0], None, [32], [0, 255])
print(hist.dtype)
plt.plot(hist, color="gray")
# 灰度等级设定为256/32 = 8
plt.xlim([0, 32])
plt.show()
eqimg = cv.equalizeHist(image[0])
cv.imshow("eq", eqimg)
# 确保均衡化的输入是一个八位(0,255)单通道图像
hist = cv.calcHist([eqimg], [0], None, [32], [0, 255])
print(hist.dtype)
plt.plot(hist, color="gray")
plt.xlim([0, 32])
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:
发现均衡化之后对比度明显提升,并且直方图高值与低值差距拉大。
学习参考
本系列所有OpenCv相关的代码示例和内容均来自博主学习的网站:opencv_course