OpenCV入门实战

运行环境:Python3.8及以上,依赖opencv-python、numpy、matplotlib

前置准备:准备face.jpg、mao.png、black.jpg三张测试图片,与python脚本放在同一目录下


一、图像金字塔(高斯金字塔+拉普拉斯金字塔)

核心原理

图像金字塔是图像多尺度表达的一种方式,主要分为高斯金字塔和拉普拉斯金字塔,区别于普通resize缩放,金字塔缩放自带高斯模糊降噪处理。

高斯金字塔分为下采样(缩小图像)和上采样(放大图像):

下采样:先高斯模糊降噪,再隔行隔列删除像素,图像长宽变为原来1/2,图像尺寸减半、分辨率降低

上采样:先对图像补0扩充尺寸,再高斯卷积插值,图像长宽变为原来2倍,放大后会丢失原图细节

拉普拉斯金字塔:用于保存图像缩放丢失的细节信息,可以依靠细节图还原模糊图像

公式:Li = Gi - pyrUp(pyrDown(Gi))

上图为高斯金字塔采样原理示意图,可以清晰看到多层金字塔尺寸变化规律,图片尺寸必须为2的整数次幂,否则会出现尺寸不匹配报错。

代码逻辑讲解

第一步:导入依赖库,统一配置matplotlib解决中文乱码问题

第二步:读取人脸灰度图,统一缩放到512*512(2的9次方,适配金字塔采样)

第三步:两次下采样,逐级缩小图像

第四步:两次上采样,分别测试原图放大、缩小后再放大两种场景

第五步:计算拉普拉斯细节图,利用细节图完成图像还原

完整代码实现

import cv2  # opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt

# 解决matplotlib中文方框+负号显示异常
plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei", "SimSun"]
plt.rcParams["axes.unicode_minus"] = False

# ----------------高斯金字塔向下采样----------------
# 读取原图并统一缩放到512×512,适配金字塔采样规则
face = cv2.imread('face.jpg', cv2.IMREAD_GRAYSCALE)
face = cv2.resize(face, (512, 512), interpolation=cv2.INTER_AREA)
cv2.imshow('face', face)
cv2.waitKey(0)

# 第一次下采样,尺寸变为原图1/2
face_down_1 = cv2.pyrDown(face)
cv2.imshow('down_1', face_down_1)
cv2.waitKey(0)

# 第二次下采样,尺寸变为原图1/4
face_down_2 = cv2.pyrDown(face_down_1)
cv2.imshow('down_2', face_down_2)
cv2.waitKey(0)

# ----------------高斯金字塔向上采样----------------
# 原图直接上采样放大2倍
face_up_1 = cv2.pyrUp(face)
cv2.imshow('up_1', face_up_1)
cv2.waitKey(0)

# 再次上采样,尺寸放大4倍
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   # 提取第一层丢失细节
L1 = face_down_1 - face_down_2_up  # 提取第二层丢失细节
fuyuan = face_down_1_up + L0 # 模糊图+细节图=还原原图

cv2.imshow('L0', L0)
cv2.imshow('L1', L1)
cv2.waitKey(0)
cv2.imshow('fuyuan', fuyuan)
cv2.waitKey(0)

代码运行结果

运行结果分析:

1. 下采样:图像逐级缩小,画面更加模糊,自带降噪效果

2. 缩小再放大:图像无法复原原图清晰度,像素信息属于永久丢失

3. 拉普拉斯金字塔:提取的细节图可以完美补全模糊图像,实现图像还原


二、图像直方图全套实操

核心原理

图像直方图是用来统计图像像素灰度分布的统计图,横坐标为像素灰度值(0-255,0代表纯黑,255代表纯白),纵坐标为对应灰度值的像素个数。

直方图只统计像素数量,不关心像素所在位置,常用于判断图像明暗、对比度、整体色调。本文实现三类直方图:

1. 灰度直方图:统计单通道灰度图像素分布

2. 彩色三通道直方图:分别统计B/G/R三通道像素分布(OpenCV通道顺序为BGR)

3. 掩膜局部直方图:只统计图片指定区域像素,屏蔽无关区域

代码逻辑讲解

第一步:灰度直方图:分别用matplotlib快速绘图、OpenCV calcHist函数自定义分箱绘图

第二步:彩色直方图:循环遍历B、G、R三个通道,分别绘制直方图曲线

第三步:掩膜直方图:创建黑色掩膜、划定白色有效区域,与原图做与运算,仅统计有效区域灰度分布

代码实现

# ----------------灰度图像直方图----------------
mao = cv2.imread('mao.png', cv2.IMREAD_GRAYSCALE)
# 方法1:matplotlib直接展平图像绘制直方图
a = mao.ravel()
plt.hist(a, bins=256)
plt.title("matplotlib灰度直方图")
plt.show()

# 方法2:OpenCV内置函数计算直方图,自定义分箱数
mao_hist = cv2.calcHist(images=[mao], channels=[0], mask=None, histSize=[16], ranges=[0, 256])
plt.plot(mao_hist)
plt.title("calcHist BINS=16 灰度直方图曲线")
plt.show()

# ----------------彩色图像三通道直方图----------------
img = cv2.imread('mao.png')
color = ('b', 'g', 'r')
# 遍历三个通道分别绘图
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()

# ----------------带Mask掩膜的局部直方图----------------
mao = cv2.imread('mao.png', cv2.IMREAD_GRAYSCALE)
cv2.imshow('mao', mao)
cv2.waitKey(0)

# 创建掩膜:黑色画布,划定矩形有效区域
mask = np.zeros(mao.shape[:2], np.uint8)
mask[50:350, 100:470] = 255
cv2.imshow('mask', mask)
cv2.waitKey(0)

# 提取掩膜选中的图像区域
mao_mask = cv2.bitwise_and(mao, mao, mask=mask)
cv2.imshow('mao_mask', mao_mask)
cv2.waitKey(0)

# 仅统计掩膜区域直方图
mao_hist_mask = cv2.calcHist(images=[mao], channels=[0], mask=mask, histSize=[256], ranges=[0, 256])
plt.plot(mao_hist_mask)
plt.title("掩膜区域局部直方图")
plt.show()

cv2.destroyAllWindows()

代码运行结果分析

1. 灰度直方图:可以直观看出图片整体偏暗还是偏亮

2. 彩色直方图:通过三条曲线分布,判断图片整体偏向蓝、绿、红哪一种色调

3. 掩膜直方图:仅统计框选区域,适合局部图像亮度分析,工程实用性极强


三、直方图均衡化图像增强

核心原理

很多实拍图片整体偏暗、对比度低、画面灰蒙蒙,直方图均衡化可以拉伸图像灰度分布区间,自动提升图像对比度,分为两种方式:

1. 全局直方图均衡化:对整张图片统一拉伸灰度,速度快,但是容易造成局部高光过曝、细节丢失

2. CLAHE自适应局部均衡化:将图片分成多个小网格,单独对每个网格做均衡化,网格之间平滑过渡,保留图像细节,避免过曝,工业项目首选

代码逻辑讲解

第一步:读取一张偏暗的灰度测试图,先绘制原图灰度直方图

第二步:调用equalizeHist实现全局均衡化,绘制均衡后直方图,拼接原图与效果图

第三步:创建CLAHE对象,设置对比度限制参数与网格大小,实现局部自适应均衡

第四步:将原图、全局均衡图、自适应均衡图三图拼接,直观对比效果差异

完整代码实现

# ----------------直方图均衡化图像增强----------------
black = cv2.imread('black.jpg', cv2.IMREAD_GRAYSCALE)
if black is None:
    raise FileNotFoundError("未找到 black.jpg,请检查文件路径")

# 绘制原图灰度直方图
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('Original_GlobalEqualize', res_global)
cv2.waitKey(0)

# 2. CLAHE自适应局部直方图均衡化
# clipLimit:对比度阈值,抑制噪点放大;tileGridSize:图像分块大小
clahe = cv2.createCLAHE(clipLimit=10, tileGridSize=(8, 8))
black_clahe = clahe.apply(black)

# 三图横向拼接对比
res_all = np.hstack((black, black_equalize, black_clahe))
cv2.imshow("Original | Global Equalize | CLAHE Adaptive Equalize", res_all)
cv2.waitKey(0)

cv2.destroyAllWindows()

代码运行结果

1. 全局均衡:整体画面提亮明显,但是人脸等细节区域出现过曝,纹理丢失

2. CLAHE自适应均衡:既提升了整体画面对比度,又完整保留局部细节,无过曝现象,实际项目优先使用


四、常见报错问题

1. 图片读取为空报错:图片名称、后缀必须和代码一致,图片与py脚本放在同一文件夹

2. matplotlib中文乱码:代码已提前配置中文字体,无需额外修改

3. 窗口卡顿无法关闭:代码末尾配置cv2.destroyAllWindows(),自动释放窗口资源

4. 金字塔尺寸报错:做金字塔采样尽量使用512*512、256*256这类2的整数次幂尺寸图片

五、全文总结

1. 图像金字塔:实现带降噪的多尺度图像缩放,缩放后图像信息不可逆丢失,可通过拉普拉斯金字塔找回细节

2. 图像直方图:快速分析图像明暗与色调,支持全局统计和局部掩膜统计

3. 直方图均衡化:低成本图像增强算法,追求细节效果直接选用CLAHE自适应均衡

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐