云计算百科
云计算领域专业知识百科平台

小白从零开始勇闯人工智能:计算机视觉初级篇(OpenCV进阶操作(上))

引言

  欢迎回来,我们已经掌握了OpenCV的基础操作如读取、显示和裁剪图像,现在我们将共同探索更高级的视觉处理技术。计算机视觉不仅仅是“看”图像,更是深入理解其内容、提取关键特征并进行分析的过程,这类似于人类通过眼睛观察世界并由大脑解析信息,而OpenCV正充当了计算机的“眼睛和大脑”。本文我们将学习图像金字塔、图像直方图、透视变换,这些技术是计算机视觉的基石,广泛应用于图像拼接、物体识别等关键领域。

一、图像金字塔——多尺度视觉分析

1、什么是图像金字塔?

  图像金字塔是计算机视觉中一种模拟多尺度观察的图像表示方法。它是通过对原始图像(金字塔底层)进行连续降采样(通常结合平滑滤波),生成一系列分辨率逐层降低的图像,并按顺序堆叠,形成从底部到顶部的“金字塔”结构。这种多尺度表达使算法能够像人类一样,既能“退后”观察整体结构与上下文,也能“走近”分析精细的局部特征。它在图像融合(如无缝拼接)、目标检测(识别不同大小的物体)等方面至关重要。最常见的类型包括用于下采样的高斯金字塔和用于重建图像细节的拉普拉斯金字塔。

2、向上采样与向下采样

向下采样(构建金字塔):

  在构建图像金字塔的向下采样过程中,随着层级向金字塔顶端移动,图像的尺寸和分辨率逐级降低。通常,每上升一层,图像的宽度和高度均缩减为原先的一半。其标准实现方法包含两个关键步骤:首先,对当前层级图像进行高斯滤波,以平滑图像并防止后续降采样产生混叠效应,接着,直接删除滤波后图像的偶数行与偶数列,从而实现尺寸的减半,生成上一层的低分辨率图像。

向上采样(重建图像):

  向上采样是图像金字塔中用于重建高分辨率图像的过程。首先,将图像的宽度和高度均扩大为原来的2倍,从而使总像素数量变为原始的4倍。此时新增的像素点暂无有效值,需要通过插值算法(如双线性插值)来估计并填充这些点的像素值。随后,通常会施加一次高斯滤波对整体图像进行平滑处理,以消除因插值可能引入的块状或不自然痕迹,使重建后的图像更加平滑自然。

  注意:向上采样和向下采样不是可逆操作!由于向下采样会丢失像素信息,即使再向上采样也无法完全恢复原始图像。

3、拉普拉斯金字塔

  拉普拉斯金字塔的构建旨在解决高斯金字塔下采样过程中信息丢失的问题。具体而言,其每一层由对应的高斯金字塔层级G_{i},减去该层先经下采样再上采样重建后的图像得出,即L_{i}=G_{i}-pyrUp(pyrDown(G_{i}))。这个差值图像捕捉了在降采样与重建过程中丢失的高频细节信息,如边缘和纹理。因此,拉普拉斯金字塔本质上是记录高斯金字塔各层间“缺失部分”的差分金字塔。

4、代码示例

   首先我们要读取灰度图像,通过两次pyrDown操作生成两层高斯金字塔。随后,通过对原图和中间层进行pyrUp上采样,并计算其与上一层图像的差值,构建出拉普拉斯金字塔的两层,这些差值图像捕捉了在下采样过程中丢失的高频细节。最后,用拉普拉斯层与上采样图像相加,来近似恢复出原始图像。                               

import cv2
import numpy as np

# 读取图像(灰度图)
face = cv2.imread('R-C.jpg', cv2.IMREAD_GRAYSCALE)

# 向下采样构建高斯金字塔
face_down_1 = cv2.pyrDown(face) # 第一层下采样
face_down_2 = cv2.pyrDown(face_down_1) # 第二层下采样

# 向上采样
face_up_1 = cv2.pyrUp(face) # 第一层上采样
face_up_2 = cv2.pyrUp(face_up_1) # 第二层上采样

# 尝试恢复:下采样后再上采样(会损失信息)
face_down_1_up = cv2.pyrUp(face_down_1)
face_down_2_up = cv2.pyrUp(face_down_2)

# 构建拉普拉斯金字塔
if face_down_1_up.shape != face.shape:
# 调整上采样图像尺寸以匹配原图
face_down_1_up = cv2.resize(face_down_1_up, (face.shape[1], face.shape[0]))

if face_down_2_up.shape != face_down_1.shape:
# 调整上采样图像尺寸以匹配原图
face_down_2_up = cv2.resize(face_down_2_up, (face_down_1.shape[1], face_down_1.shape[0]))

L0 = face – face_down_1_up # 第0层拉普拉斯金字塔
L1 = face_down_1 – face_down_2_up # 第1层拉普拉斯金字塔

# 尝试用拉普拉斯金字塔恢复图像
fuyuan = face_down_1_up + L0

# 显示结果
cv2.imshow('Original', face)
cv2.imshow('Down 1', face_down_1)
cv2.imshow('Down 2', face_down_2)

# 对拉普拉斯金字塔进行归一化以便显示
L0_display = cv2.normalize(L0, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
cv2.imshow('Laplacian L0', L0_display)
cv2.waitKey(0)
cv2.destroyAllWindows()

二、图像直方图——图像的"DNA分析"

1、什么是直方图?

  直方图是图像处理中一种基础的统计工具,它以图形化的方式直观展示了图像中所有像素的强度值分布情况,如同图像的“指纹”或“DNA”。它通过计算并绘制每个特定像素强度值在整幅图像中出现的频率或次数,来精确描述图像的明暗构成。通过观察直方图的形状与分布范围,我们可以直接解读出图像的关键特性,例如整体亮度倾向、对比度高低以及细节层次的丰富程度,这些信息是进行图像分析、增强和调整的重要依据。

2、直方图的核心概念:Bins(区间)

  直方图通过统计图像中像素强度的分布来揭示其内在特征,其*Bins(区间)是其核心结构。为了便于分析,连续的像素值范围(如0-255)被划分为若干个连续的子区间,每个区间称为一个Bin。统计落入每个Bin的像素数量,便形成了描述图像亮度、对比度等特性的分布图表。这种方法不仅减少了计算量,还能突出主要分布模式。

对于灰度图像,像素值范围是0-255共256个可能值。我们可以将这个范围划分为多个子区间:

[0,255]=[0,15]∪[16,31]∪…∪[240,255]

3、代码示例

  我们首先要读取一张灰度图像,之后有三种方法:第一种方法直接使用Matplotlib的hist函数,将图像展平为一维数组并绘制256个区间的完整直方图。第二种方法调用OpenCV的calcHist函数,将像素强度范围划分为16个区间(Bins)进行统计,生成更为概括的分布图表,从而突出主要亮度特征。第三种方法则针对彩色图像,分别计算蓝、绿、红三个颜色通道的256区间直方图,并在同一图表中叠加显示,以分析各通道的色彩分布情况。

import cv2
import matplotlib.pyplot as plt
import numpy as np

# 读取图像
phone = cv2.imread('phone.png', cv2.IMREAD_GRAYSCALE)

# 方法1:使用matplotlib直接绘制直方图
plt.figure(figsize=(12, 5))

plt.subplot(1, 3, 1)
plt.hist(phone.ravel(), bins=256) # ravel将多维数组展平为一维
plt.title('Matplotlib Histogram')

# 方法2:使用OpenCV计算直方图
phone_hist = cv2.calcHist([phone], [0], None, [16], [0, 256])

plt.subplot(1, 3, 2)
plt.plot(phone_hist)
plt.title('OpenCV Histogram (16 bins)')

# 方法3:彩色图像直方图
img = cv2.imread('phone.png')
colors = ('b', 'g', 'r')
plt.subplot(1, 3, 3)
for i, color in enumerate(colors):
histr = cv2.calcHist([img], [i], None, [256], [0, 256])
plt.plot(histr, color=color)
plt.title('Color Histogram')

plt.tight_layout()
plt.show()

掩膜(Mask)操作:局部直方图分析:

  有时我们只关心图像的某一部分,这时可以使用掩膜:

# 创建掩膜
mask = np.zeros(phone.shape[:2], np.uint8)
mask[50:350, 100:470] = 255 # 只关注中心区域

# 应用掩膜
phone_masked = cv2.bitwise_and(phone, phone, mask=mask)

# 计算掩膜区域的直方图
phone_hist_mask = cv2.calcHist([phone], [0], mask, [256], [0, 256])

# 显示结果
cv2.imshow('Original', phone)
cv2.imshow('Mask', mask)
cv2.imshow('Masked Image', phone_masked)
cv2.waitKey(0)

plt.figure()
plt.plot(phone_hist_mask)
plt.title('Masked Region Histogram')
plt.show()

直方图均衡化:增强图像对比度:

  直方图均衡化是一种强大的图像增强技术,通过重新分布像素值来增加图像对比度:

import cv2
import matplotlib.pyplot as plt
import numpy as np

# 读取低对比度图像
img = cv2.imread('R-C.jpg', cv2.IMREAD_GRAYSCALE)

# 全局直方图均衡化
img_equalized = cv2.equalizeHist(img)

# 自适应直方图均衡化(局部处理,保留更多细节)
clahe = cv2.createCLAHE(clipLimit=1.0, tileGridSize=(16, 16))
img_clahe = clahe.apply(img)

# 显示对比
plt.figure(figsize=(15, 5))

plt.subplot(1, 4, 1)
plt.hist(img.ravel(), bins=256)
plt.title('Original Histogram')

plt.subplot(1, 4, 2)
plt.hist(img_equalized.ravel(), bins=256)
plt.title('Global Equalization')

plt.subplot(1, 4, 3)
plt.hist(img_clahe.ravel(), bins=256)
plt.title('CLAHE Histogram')

# 图像对比
result = np.hstack((img, img_equalized, img_clahe))
plt.subplot(1, 4, 4)
plt.imshow(result, cmap='gray')
plt.title('Image Comparison')

plt.tight_layout()
plt.show()

三、透视变换——矫正图像视角

1、什么是透视变换?

  透视变换是一种核心的图像几何变换技术,它通过一个3×3的变换矩阵,将图像从一个三维空间的观察平面投影到另一个全新的视平面上。这个过程模拟了人类视觉或相机镜头的透视效果,能够改变图像的视角。其最典型的应用是“矫正”因拍摄角度导致的几何形变,例如将一张倾斜拍摄的名片图像,变换为规整的正面向视图。与仅能处理旋转、缩放和平移的仿射变换不同,透视变换可以处理“近大远小”的深度感变化,使得原本平行的直线在变换后可能不再平行,从而实现了更复杂和真实的视角转换。

2、OpenCV中的透视变换

  首先我们要读取图像并定义两组对应的关键点:一组是原始图像中待矫正区域的四个角点,另一组是这些点矫正后应位于的目标标准矩形位置。接着,通过cv2.getPerspectiveTransform函数根据这两组点计算出一个3×3的透视变换矩阵M。最后,使用cv2.warpPerspective函数将原始图像应用该矩阵进行变换,生成一幅视角被“拉正”的新图像。

import cv2
import numpy as np

def perspective_transform_demo():
# 读取图像
img = cv2.imread('R-C.jpg')
h, w = img.shape[:2]
print(f"图像尺寸:宽度={w}, 高度={h}")

# 定义原始点(通常在图像中标记文档的四个角)
src_points = np.float32([
[50, 50], # 左上角
[w – 50, 100], # 右上角
[w – 100, h – 50], # 右下角
[100, h – 100] # 左下角
])

# 定义目标点(矫正后的位置)
dst_points = np.float32([
[0, 0], # 左上角
[w, 0], # 右上角
[w, h], # 右下角
[0, h] # 左下角
])

# 计算透视变换矩阵
M = cv2.getPerspectiveTransform(src_points, dst_points)

# 应用透视变换
warped = cv2.warpPerspective(img, M, (w, h))

# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Perspective Transformed', warped)
cv2.waitKey(0)
cv2.destroyAllWindows()

return M

# 调用函数
M = perspective_transform_demo()

赞(0)
未经允许不得转载:网硕互联帮助中心 » 小白从零开始勇闯人工智能:计算机视觉初级篇(OpenCV进阶操作(上))
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!