OpenCV 图像直方图、金字塔、直方图均衡完整实战教程
·
文章前言
在数字图像处理中,直方图是描述图像像素灰度分布最基础的工具,结合图像金字塔、掩膜、直方图均衡化,可以实现图像分层分解、局部像素统计、暗光图像增强等经典功能。本文整合全套实战代码,包含:图像金字塔(高斯 / 拉普拉斯)、灰度直方图、彩色直方图、掩膜局部直方图、全局直方图均衡、自适应 CLAHE 均衡,逐段讲解原理与代码,适合 OpenCV 图像处理入门学习。
目录
参数详解 cv2.calcHist(images, channels, mask, histSize, ranges)
环境依赖
pip install opencv-python numpy matplotlib
一、图像金字塔:高斯金字塔 + 拉普拉斯金字塔
1. 核心原理
- 高斯下采样
pyrDown():图像宽高各缩小 1/2,高斯模糊后丢弃偶数行 / 列,构建高斯金字塔(逐层缩小) - 高斯上采样
pyrUp():图像宽高扩大 2 倍,空白像素补 0 后高斯模糊,放大图像 - 拉普拉斯金字塔:原图 - 原图下采样再上采样的图像,存储图像细节(边缘、纹理),可用于图像复原、图像融合。
完整代码
import cv2
import numpy as np
# 读取灰度图片
face = cv2.imread('avril lavigne.jpg', cv2.IMREAD_GRAYSCALE)
# 统一缩放尺寸
face = cv2.resize(face, (800, 1204))
cv2.imshow('原图face', face)
cv2.waitKey(0)
# ========== 高斯金字塔:下采样缩小 ==========
face_down_1 = cv2.pyrDown(face) # 第1层缩小
cv2.imshow('down_1 一级下采样', face_down_1)
cv2.waitKey(0)
face_down_2 = cv2.pyrDown(face_down_1) # 第2层缩小
cv2.imshow('down_2 二级下采样', face_down_2)
cv2.waitKey(0)
# ========== 高斯上采样放大 ==========
face_up_1 = cv2.pyrUp(face)
cv2.imshow('up_1 原图直接放大', face_up_1)
cv2.waitKey(0)
face_up_2 = cv2.pyrUp(face_up_1)
cv2.imshow('up_2 二次放大', face_up_2)
cv2.waitKey(0)
# 缩小后再放大,和原图做差值得到拉普拉斯层
face_down_1_up = cv2.pyrUp(face_down_1)
face_down_2_up = cv2.pyrUp(face_down_2)
cv2.imshow('down_1_up 一级缩小后复原', face_down_1_up)
cv2.imshow('down_2_up 二级缩小后复原', face_down_2_up)
cv2.waitKey(0)
# ========== 拉普拉斯金字塔:提取图像细节 ==========
L0 = face - face_down_1_up # 第0层拉普拉斯(原图细节)
L1 = face_down_1 - face_down_2_up # 第1层拉普拉斯(缩小图细节)
cv2.imshow('L0 原图细节层', L0)
cv2.imshow('L1 一级缩小细节层', L1)
cv2.waitKey(0)
# 图像复原:放大图 + 拉普拉斯细节 = 还原原图
fuyuan = face_down_1_up + L0
cv2.imshow('复原图像', fuyuan)
cv2.waitKey(0)
cv2.destroyAllWindows()
关键知识点总结
- 下采样会丢失细节,直接放大图像会模糊;
- 拉普拉斯金字塔保存丢失的细节信息,复原时叠加即可恢复清晰图像;
- 应用场景:图像融合、图像拼接、纹理提取。
二、图像灰度直方图两种绘制方式
1. 函数介绍
numpy.ravel():将二维图像矩阵展平为一维像素数组,方便统计灰度;plt.hist():matplotlib 一键绘制柱状直方图,简单直观;cv2.calcHist():OpenCV 原生直方图计算函数,专业图像处理接口,支持自定义区间、掩膜、多通道。
完整代码
import cv2
import matplotlib.pyplot as plt
# 1. 以灰度模式读取图片
phone = cv2.imread('phone.png', cv2.IMREAD_GRAYSCALE)
# 2. ravel将二维图像展平为一维像素数组
pixel_arr = phone.ravel()
# 方式1:Matplotlib快速绘制灰度柱状直方图
# bins=256:0~255每个灰度单独一个区间
plt.hist(pixel_arr, bins=256)
plt.title("Matplotlib 灰度直方图 bins=256")
plt.show()
# 方式2:OpenCV calcHist计算直方图,折线展示
# 参数说明:[图像], [通道0灰度图], 无掩模, 划分16个区间, 像素范围0~256
phone_hist = cv2.calcHist([phone], [0], None, [16], [0, 256])
plt.plot(phone_hist)
plt.title("OpenCV calcHist 直方图曲线 histSize=16")
plt.show()
参数详解 cv2.calcHist(images, channels, mask, histSize, ranges)
images:输入图像列表,必须用[]包裹;channels:统计通道,灰度图固定[0],彩色 BGR 对应[0][1][2];mask:掩膜,只统计指定区域,全图统计填None;histSize(BINS):灰度区间划分数,256 代表每个灰度单独统计,16 代表合并 16 个灰度为一段;ranges:像素取值范围,灰度图固定[0,256](左闭右开,覆盖 0~255)。
三、彩色直方图 + Mask 掩膜局部直方图
1. 彩色直方图原理
彩色图为 BGR 三通道,单独计算每个通道的像素分布,分别绘制蓝、绿、红三条曲线。
2. Mask 掩膜原理
创建全黑图像,指定区域置 255 白色,通过bitwise_and截取图像局部,仅统计白色区域的直方图。
完整代码
import cv2
import numpy as np
import matplotlib.pyplot as plt
# ====================== 1. 彩色三通道直方图 ======================
img = cv2.imread('phone.png')
color = ('b', 'g', 'r')
# 遍历BGR三个通道,分别计算并绘制直方图
for i, col in enumerate(color):
histr = cv2.calcHist(images=[img], channels=[i], mask=None, histSize=[256], ranges=[0, 256])
plt.plot(histr, color=col)
plt.title("BGR彩色通道直方图")
plt.show()
# ====================== 2. Mask掩膜局部直方图 ======================
# 读取灰度图
phone = cv2.imread('phone.png', cv2.IMREAD_GRAYSCALE)
cv2.imshow('原图phone', phone)
cv2.waitKey(0)
# 创建和图像同尺寸的全黑掩膜
mask = np.zeros(phone.shape[:2], np.uint8)
# 指定矩形区域设置为白色255,仅该区域参与统计
mask[50:350, 100:470] = 255
cv2.imshow('mask掩膜', mask)
cv2.waitKey(0)
# 按位与运算,提取掩膜对应图像区域
phone_mask = cv2.bitwise_and(phone, phone, mask=mask)
cv2.imshow('掩膜截取局部图像', phone_mask)
cv2.waitKey(0)
# 仅计算掩膜区域的直方图
phone_hist_mask = cv2.calcHist(images=[phone], channels=[0], mask=mask, histSize=[256], ranges=[0, 256])
plt.plot(phone_hist_mask)
plt.title("掩膜局部区域直方图")
plt.show()
cv2.destroyAllWindows()
四、直方图均衡化:全局均衡 + 自适应 CLAHE 均衡
核心作用
针对暗光、低对比度图像,拉伸灰度动态范围,提升画面亮度与细节;分为两种方案:
- 全局均衡
equalizeHist:整张图像统一均衡,强光区域容易过曝、噪声放大; - 自适应均衡 CLAHE:将图像分小块单独均衡,块间插值平滑,保留局部对比度,效果更自然。
完整代码
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取暗光灰度图
black = cv2.imread('black.jpg', cv2.IMREAD_GRAYSCALE)
# 绘制原图灰度分布直方图
plt.hist(black.ravel(), bins=256)
plt.title("原图直方图")
plt.show()
# 1. 全局直方图均衡化
black_equalize = cv2.equalizeHist(black)
plt.hist(black_equalize.ravel(), bins=256)
plt.title("全局均衡后直方图")
plt.show()
# 原图与全局均衡图横向拼接对比
res_global = np.hstack((black, black_equalize))
cv2.imshow('原图 | 全局均衡化', res_global)
cv2.waitKey(0)
# 2. 自适应直方图均衡化 CLAHE
# clipLimit:对比度限制阈值,抑制噪声放大;tileGridSize:图像分块大小
clahe = cv2.createCLAHE(clipLimit=10, tileGridSize=(8, 8))
black_clahe = clahe.apply(black)
# 原图、全局均衡、CLAHE自适应均衡 三图拼接对比
res_all = np.hstack((black, black_equalize, black_clahe))
cv2.imshow('原图 | 全局均衡 | CLAHE自适应均衡', res_all)
cv2.waitKey(0)
cv2.destroyAllWindows()
两种均衡对比
表格
| 均衡方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| equalizeHist 全局均衡 | 操作简单,整体提亮明显 | 局部过曝,噪声放大 | 整体极暗、无明显高光的图像 |
| CLAHE 自适应均衡 | 分块处理,保留细节,抑制过曝 | 参数需要微调 | 人像、风景、明暗分布不均的图像 |
五、全文总结
- 图像金字塔:
pyrDown缩小、pyrUp放大,拉普拉斯金字塔提取图像细节,用于图像融合复原; - 直方图统计:
plt.hist快速绘图,cv2.calcHist专业计算,支持灰度、彩色、掩膜局部统计; - 图像增强:直方图均衡化拉伸灰度,全局均衡速度快,CLAHE 自适应均衡视觉效果更佳;
- 工程使用建议:日常图像增强优先使用CLAHE 自适应均衡,需要局部像素分析时配合 Mask 掩膜使用。
更多推荐



所有评论(0)