3. 直方图归一化处理
任务说明
本案例针对一幅灰度图像,计算其灰度直方图,并将直方图各灰度级的频数除以像素总数,得到归一化的概率分布(即每个灰度级出现的概率),最后验证所有概率之和等于1。归一化直方图是直方图均衡化、规定化等后续处理的基础,它使直方图不再依赖图像尺寸,便于不同图像之间进行概率意义上的比较。
实现方案
使用Python与OpenCV读取灰度图像,通过NumPy计算直方图并完成归一化。核心步骤为:读取图像→统计各灰度级像素个数→除以总像素数得到概率→累加验证。代码不依赖任何未展示的预定义变量,输入图像路径由用户指定,若图像本身为彩色则先转换为灰度图。
代码实现
import cv2
import numpy as np
def normalize_histogram(image_path):
"""
读取灰度图像,计算归一化直方图(概率分布),并验证概率之和为1。
参数:
image_path: 输入图像路径(支持彩色或灰度图,彩色图自动转灰度)
返回:
hist_prob: 长度为256的numpy数组,hist_prob[k]为灰度级k出现的概率
total_prob: 所有概率之和(应等于1.0)
"""
# 1. 读取图像并转为灰度
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError(f"无法读取图像: {image_path}")
# 2. 获取图像尺寸
h, w = img.shape
total_pixels = h * w
# 3. 计算直方图(256个灰度级)
hist = cv2.calcHist([img], [0], None, [256], [0, 256]).flatten()
# 4. 归一化:频数 / 总像素数
hist_prob = hist / total_pixels
# 5. 验证概率之和
total_prob = np.sum(hist_prob)
return hist_prob, total_prob
# 使用示例(请将路径替换为实际图像路径)
if __name__ == "__main__":
# 生成一张测试图像(8x8灰度图,便于人工验证)
test_img = np.array([
[0, 0, 1, 1, 2, 2, 3, 3],
[0, 0, 1, 1, 2, 2, 3, 3],
[4, 4, 5, 5, 6, 6, 7, 7],
[4, 4, 5, 5, 6, 6, 7, 7],
[8, 8, 9, 9, 10, 10, 11, 11],
[8, 8, 9, 9, 10, 10, 11, 11],
[12, 12, 13, 13, 14, 14, 15, 15],
[12, 12, 13, 13, 14, 14, 15, 15]
], dtype=np.uint8)
cv2.imwrite("test_gray.png", test_img)
prob, total = normalize_histogram("test_gray.png")
# 打印非零概率值(便于观察)
print("灰度级 概率")
for k in range(256):
if prob[k] > 0:
print(f"{k:3d} {prob[k]:.4f}")
print(f"\n概率总和: {total:.6f}")
print(f"验证结果: {'通过' if abs(total - 1.0) < 1e-6 else '失败'}")
运行与验证
依赖环境:Python 3.6+,安装OpenCV(pip install opencv-python)和NumPy(pip install numpy)。
运行方式:直接执行上述脚本。脚本会生成一张8×8的测试图像(灰度级0~15各出现4次,共64像素),然后调用归一化函数处理该图像。
预期输出:由于测试图像中每个灰度级出现4次,总像素64个,因此每个非零灰度级的概率应为4/64=0.0625。程序将打印16个非零概率值(灰度级0~15),每个均为0.0625,最后输出概率总和为1.000000,并显示“验证结果: 通过”。
判定标准:若打印的概率总和与1.0的误差小于1e-6,且每个灰度级概率等于其像素数除以总像素数,则案例实现正确。对于任意输入图像,归一化直方图的所有概率之和恒为1(浮点精度范围内),这是概率分布的基本性质。