OpenCV快速入门:图像分析——傅里叶变换、积分图像


前言

在当今数字时代,图像无处不在,而图像分析成为解读、理解和处理这些图像的关键技术之一。本文将介绍图像分析的基础知识,并结合OpenCV中的强大功能,深入探讨图像分析的傅里叶变换、积分图像。
在这里插入图片描述

一、傅里叶变换

1.1 离散傅里叶变换

傅里叶变换是一种强大的数学工具,常用于将信号从时域转换到频域。在图像处理领域,离散傅里叶变换是一项重要而常用的技术,它能够将图像表示为不同频率分量的集合,为后续的图像分析提供了丰富的信息。

1.1.1 离散傅里叶变换原理

离散傅里叶变换(Discrete Fourier Transform,DFT)通过将一个离散序列(如图像中的像素值)转换为一组复数,表示原始序列中不同频率的分量。其原理基于复数的正弦和余弦函数,通过这些函数的组合,可以表示原始信号在频域中的分布情况。

1.1.2 离散傅里叶变换公式

傅里叶变换的数学表达式如下:

F ( u , v ) = ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) ⋅ e − j 2 π ( u x M + v y N ) F(u, v) = \sum_{x=0}^{M-1} \sum_{y=0}^{N-1} f(x, y) \cdot e^{-j2\pi\left(\frac{ux}{M} + \frac{vy}{N}\right)} F(u,v)=x=0M1y=0N1f(x,y)ej2π(Mux+Nvy)

其中, f ( x , y ) f(x, y) f(x,y) 是输入图像的像素值, F ( u , v ) F(u, v) F(u,v) 是变换后的频域表示, M M M N N N 分别是图像的宽度和高度, u u u v v v 是频域中的坐标。

  • f ( x , y ) f(x, y) f(x,y): 输入图像在时域中的像素值。
  • F ( u , v ) F(u, v) F(u,v): 输出图像在频域中的表示。
  • e − j 2 π ( u x M + v y N ) e^{-j2\pi\left(\frac{ux}{M} + \frac{vy}{N}\right)} ej2π(Mux+Nvy): 复指数项,描述了正弦和余弦函数的组合,表示不同频率分量的贡献。

1.1.3 代码实现

在OpenCV中,进行离散傅里叶变换可以使用cv2.dft函数。以下是一个简单的例子:

import cv2
import numpy as np

# 读取图像
img = cv2.imread('tulips.jpg', 0)

# 进行傅里叶变换
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)

# 将变换后图像的低频部分转移到图像的中心
dft_shift = np.fft.fftshift(dft)

# 计算幅度谱
magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))
# 将结果标准化到0~255
magnitude_spectrum_normalized = cv2.normalize(magnitude_spectrum, None, 0, 255, cv2.NORM_MINMAX)

# 显示频谱图像
cv2.imshow('Magnitude Spectrum', cv2.hconcat([img, np.uint8(magnitude_spectrum_normalized)]))
cv2.waitKey(0)
cv2.destroyAllWindows()

magnitude_spectrum 是通过对傅里叶变换的结果进行处理而得到的图像,表示了图像在频域中的幅度信息。
Magnitude Spectrum
cv2.magnitude 是OpenCV中用于计算二维向量幅度的函数。在频域中,图像被表示为复数,包括实部和虚部。幅度谱是通过计算复数的幅度(模)得到的,其数学定义为:

A ( u , v ) = R ( u , v ) 2 + I ( u , v ) 2 A(u, v) = \sqrt{R(u, v)^2 + I(u, v)^2} A(u,v)=R(u,v)2+I(u,v)2

其中, A ( u , v ) A(u, v) A(u,v) 是频域中的幅度谱, R ( u , v ) R(u, v) R(u,v) I ( u , v ) I(u, v) I(u,v) 分别是傅里叶变换结果的实部和虚部。

对于图像处理而言,cv2.magnitude 的主要作用在于可视化图像中不同频率分量的强度。在生成的图像中,亮度较高的区域表示具有较大幅度的频率分量,而亮度较低的区域表示幅度较小的频率分量。

通常,频谱中心附近的低频分量会占据亮度较高的区域,而高频分量则分布在图像的边缘。通过观察 cv2.magnitude,我们可以了解图像中哪些频率分量对图像的整体特征起到了关键作用。这对于识别图像中的纹理、边缘等特征是非常有帮助的。

在实际图像处理中,cv2.magnitude 的应用不仅限于观察,还可以用于一些频域滤波操作,如频域滤波器的设计和应用,以实现图像增强、去噪等目的。

1.1.4 cv2.dft 函数解析

cv2.dft 方法是 OpenCV 中用于执行一维或二维离散傅里叶变换的函数。该函数支持多种变换类型和操作模式,能够对输入的实数或复数数组进行傅里叶变换。以下是对 cv2.dft 方法的简要说明:
参数:

  • src: 输入图像,数据类型为浮点型或复数型的 numpy 数组。
  • dst: 输出数组,用于存储变换结果。如果未提供,则函数会创建一个具有相同类型和大小的数组。
  • flags: 变换标志,控制傅里叶变换的行为。常用的标志包括:
    • cv2.DFT_COMPLEX_OUTPUT: 输出为复数数组,包含实部和虚部。
    • cv2.DFT_SCALE: 缩放变换的结果,使其适应图像显示。
    • cv2.DFT_INVERSE: 执行逆傅里叶变换,将频域信号转换回空域。
  • nonzeroRows: 用于优化计算的参数,通常可以设置为输入图像的行数。

功能:

  • 执行离散傅里叶变换(DFT): 将输入图像从空域转换到频域,得到包含频率分量的复数数组。
  • 可选的缩放: 通过设置 cv2.DFT_SCALE 标志,可以对变换结果进行缩放,以适应图像显示。
  • 逆变换: 如果设置了 cv2.DFT_INVERSE 标志,则执行逆傅里叶变换,将频域信号转换回空域。

1.2 傅里叶变换进行卷积

1.2.1 傅里叶变换卷积原理

傅里叶变换在图像处理中的卷积操作是一种强大而高效的技术。卷积是一种将两个函数产生第三个函数的数学运算,而傅里叶变换能够在频域中简化卷积运算,提高计算效率。在图像处理中,这意味着通过傅里叶变换,我们可以用更快的方式对图像进行滤波和特征提取。

1.2.2 傅里叶变换卷积公式

傅里叶变换的卷积定理表述为:

g ( x , y ) = f ( x , y ) ∗ h ( x , y )   → 傅里叶频域   G ( u , v ) = F ( u , v ) ⋅ H ( u , v ) g(x, y) = f(x, y) * h(x, y) \ \xrightarrow{\mathcal{傅里叶频域}} \ G(u, v) = F(u, v) \cdot H(u, v) g(x,y)=f(x,y)h(x,y) 傅里叶频域  G(u,v)=F(u,v)H(u,v)

其中, g ( x , y ) g(x, y) g(x,y) 是图像 f ( x , y ) f(x, y) f(x,y) 和滤波器 h ( x , y ) h(x, y) h(x,y) 的卷积结果, G ( u , v ) G(u, v) G(u,v) 是它们在频域中的对应。符号 ⋅ \cdot 表示点乘。

1.2.3 代码实现

在OpenCV中,可以通过以下简单的代码演示傅里叶变换进行卷积的过程:

import cv2
import numpy as np

# 读取图像
img = cv2.imread('tulips.jpg', 0)

# 创建简单的均值滤波器
kernel = np.ones((5, 5), np.float32) / 25

# 在空间域执行卷积
conv_img = cv2.filter2D(img, -1, kernel)

# 创建更大的数组 tempA 和 tempB
x_img, y_img = img.shape
x_kel, y_kel = kernel.shape

tempA = np.zeros((x_img + x_kel - 1, y_img + y_kel - 1))
tempB = np.zeros((x_img + x_kel - 1, y_img + y_kel - 1))

# 将图像复制到 tempA 的中心位置
tempA[int((x_kel - 1) / 2):int(x_img + (x_kel - 1) / 2),
int((y_kel - 1) / 2):int(y_img + (y_kel - 1) / 2)] = img

# 将卷积核复制到 tempB 的中心位置
tempB[int(tempB.shape[0] / 2 - (x_kel - 1) / 2):int(tempB.shape[0] / 2 + (x_kel - 1) / 2 + 1),
int(tempB.shape[1] / 2 - (y_kel - 1) / 2):int(tempB.shape[1] / 2 + (y_kel - 1) / 2 + 1)] = kernel

# 在频率域执行卷积
dft_A = cv2.dft(tempA.astype(np.float32), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_B = cv2.dft(tempB.astype(np.float32), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_c = cv2.mulSpectrums(dft_A, dft_B, 0)

img_filtered = cv2.idft(dft_c)
img_filtered = np.fft.ifftshift(img_filtered)
img_filtered = cv2.magnitude(img_filtered[:, :, 0], img_filtered[:, :, 1]) / tempA.size

img_filtered = cv2.normalize(img_filtered, None, 0, 255, cv2.NORM_MINMAX)
img_filtered = np.array(img_filtered, dtype="uint8")

# 裁剪 img_filtered 以匹配原始图像的大小
img_filtered = img_filtered[int((x_kel - 1) / 2):int(x_img + (x_kel - 1) / 2),
               int((y_kel - 1) / 2):int(y_img + (y_kel - 1) / 2)]


# 共享的参数
shared_params = {
    
    
    "org": (10, 30),
    "fontFace": cv2.FONT_HERSHEY_SIMPLEX,
    "fontScale": 1,
    "thickness": 2,
    "color": 255,
    "lineType": cv2.LINE_AA,
}
# 显示结果
cv2.putText(img, "Original Image", **shared_params)
cv2.putText(conv_img, "Filtered Image", **shared_params)
cv2.putText(img_filtered, "Fourier Transform", **shared_params)

cv2.imshow('Convolution', cv2.hconcat([img, conv_img, img_filtered]))
cv2.waitKey(0)
cv2.destroyAllWindows()

Convolution

1.2.4 cv2.mulSpectrums 函数解析

cv2.mulSpectrums 是OpenCV中用于执行两个傅里叶频谱的逐元素相乘的函数。以下是对该函数的参数和功能的简要说明:
参数:

  • a: 第一个输入数组,是一个傅里叶变换的频谱(复数数组)。
  • b: 第二个输入数组,与第一个数组的大小和类型相同,同样是一个傅里叶变换的频谱(复数数组)。
  • flags: 操作标志,目前支持的唯一标志是 cv2.DFT_ROWS,用于指示每行都是独立的1D傅里叶频谱。如果不使用该标志,可以将其设为 0
  • c: 输出数组,用于存储两个输入数组逐元素相乘的结果。如果未提供,函数会创建一个具有相同类型和大小的数组。
  • conjB: 可选标志,用于指示是否在相乘之前对第二个输入数组进行共轭。如果设为 True,则进行共轭。

功能:

  • 逐元素相乘: 对两个傅里叶频谱进行逐元素相乘,即将它们的实部和虚部分别相乘。
  • 可选的行操作: 如果设置了 cv2.DFT_ROWS 标志,将每一行视为独立的1D傅里叶频谱进行相乘。
  • 可选的共轭操作: 如果设置了 conjBTrue,将对第二个输入数组进行共轭操作。

使用示例:

import cv2
import numpy as np

# 生成两个傅里叶频谱
a = cv2.dft(np.random.rand(4, 4), flags=cv2.DFT_COMPLEX_OUTPUT)
b = cv2.dft(np.random.rand(4, 4), flags=cv2.DFT_COMPLEX_OUTPUT)

# 将频谱进行逐元素相乘
result = cv2.mulSpectrums(a, b, 0)

# 打印结果
print(result)

上述代码演示了如何使用 cv2.mulSpectrums 对两个傅里叶频谱进行逐元素相乘。这种操作在图像处理中的卷积和相关运算中经常使用,可以高效地实现频域操作。

1.3 离散余弦变换

1.3.1 离散余弦变换原理

离散余弦变换是一种将信号从时域转换到频域的方法,广泛应用于图像和音频压缩等领域。在DCT中,信号被表示为一组余弦函数的线性组合。与傅里叶变换不同,DCT对于实际应用更为友好,因为它在表示图像中的能量分布时更加集中。

1.3.2 离散余弦变换公式

DCT的一维变换公式为:

F ( u ) = C ( u ) ∑ x = 0 N − 1 f ( x ) cos ⁡ [ ( 2 x + 1 ) u π 2 N ] F(u) = C(u) \sum_{x=0}^{N-1} f(x) \cos\left[\frac{(2x + 1)u\pi}{2N}\right] F(u)=C(u)x=0N1f(x)cos[2N(2x+1)uπ]

其中, F ( u ) F(u) F(u) 是变换后的频率分量, f ( x ) f(x) f(x) 是输入信号, C ( u ) C(u) C(u) 是归一化系数, N N N 是信号的长度, u u u 是频率索引。

对于二维图像,DCT变换公式为:
D C T ( u , v ) = C ( u ) C ( v ) ∑ i = 0 N − 1 ∑ j = 0 M − 1 f ( i , j ) cos ⁡ ( ( 2 i + 1 ) u π 2 N ) cos ⁡ ( ( 2 j + 1 ) v π 2 M ) DCT(u, v) = C(u)C(v)\sum_{i=0}^{N-1}\sum_{j=0}^{M-1}f(i, j) \cos\left(\frac{(2i+1)u\pi}{2N}\right)\cos\left(\frac{(2j+1)v\pi}{2M}\right) DCT(u,v)=C(u)C(v)i=0N1j=0M1f(i,j)cos(2N(2i+1)uπ)cos(2M(2j+1)vπ)

其中, f ( i , j ) f(i, j) f(i,j) 是图像在位置 ( i , j ) (i, j) (i,j) 处的像素值, D C T ( u , v ) DCT(u, v) DCT(u,v) 是变换后的系数, C ( u ) C(u) C(u) C ( v ) C(v) C(v) 是归一化系数。

在离散余弦变换(DCT)的公式中, C ( u ) C(u) C(u) 是归一化系数,其取值范围是与信号长度 N N N 有关的。一般而言,DCT的归一化系数
C ( u ) C(u) C(u) 可以通过以下公式计算:

C ( u ) = { 2 N , u = 0 2 N cos ⁡ ( ( 2 u + 1 ) π 2 N ) , u > 0 C(u) =\begin{cases} \sqrt{\frac{2}{N}}, &u = 0 \\ \sqrt{\frac{2}{N}} \cos\left(\frac{(2u + 1)\pi}{2N}\right), &u > 0 \end{cases} C(u)= N2 ,N2 cos(2N(2u+1)π),u=0u>0

其中, u u u 是频率索引, N N N 是信号的长度。

这意味着当 u u u 等于 0 时,归一化系数 C ( u ) C(u) C(u) 的取值为 2 N \sqrt{\frac{2}{N}} N2 ,而当 u u u 大于 0 时,其取值为 2 N \sqrt{\frac{2}{N}} N2 与余弦函数的乘积。

要注意的是,不同的DCT变种可能存在稍微不同的归一化系数计算方式。在实际应用中,可以根据使用的DCT变种进行相应的归一化系数计算。

1.3.3 代码实现

在OpenCV中,可以使用 cv2.dct 函数来进行离散余弦变换。以下是一个简单的示例代码:

import cv2
import numpy as np

# 读取图像
image = cv2.imread('tulips.jpg', 0)

# 进行离散余弦变换
dct_result = cv2.dct(image.astype(np.float32))
# 使用 np.clip 将数据限制在一个合理的范围内,避免出现无效值
dct_result = np.clip(dct_result, 1e-10, None)  # 1e-10 是一个很小的正数,可以根据实际情况调整
# 计算幅度谱
log_dct_result = 20 * np.log(dct_result)
log_dct_result = np.clip(log_dct_result, 0, 255)

# 显示频谱图像
cv2.imshow('DCT Transform', cv2.hconcat([image, np.uint8(log_dct_result)]))
cv2.waitKey(0)
cv2.destroyAllWindows()

DCT Transform
上述代码演示了如何使用 cv2.dct 对图像进行离散余弦变换,并通过对数尺度来可视化变换后的结果。通过这一变换,图像在频域中的能量分布被更好地集中在低频部分。

1.3.4 cv2.dct函数解析

cv2.dct 是OpenCV中用于执行离散余弦变换(DCT)的函数。以下是对该函数的参数和功能的简要说明:

参数:

  • src: 输入浮点数组,可以是一维或二维的。表示需要进行离散余弦变换的原始数据。
  • dst: 输出数组,用于存储变换结果。如果未提供,函数会创建一个具有相同类型和大小的数组。
  • flags: 变换标志,控制变换的模式和方向。可以通过位运算组合不同的标志。主要的标志有:
    • cv2.DCT_FORWARD: 执行正向DCT(默认)。
    • cv2.DCT_INVERSE: 执行反向DCT,将DCT的结果转换回原始数据。
    • cv2.DCT_ROWS: 指示对每一行进行1D DCT变换。

功能:

  • 一维或二维DCT: 根据输入数组的维度,执行一维或二维的离散余弦变换。
  • 正向或反向变换: 可以选择执行正向DCT(默认)或反向DCT,根据设置的 flags
  • 行变换: 如果设置了 cv2.DCT_ROWS 标志,将对每一行执行1D DCT变换。

1.4 傅里叶逆变换

在图像处理中,傅里叶逆变换是傅里叶变换的逆过程,它允许我们从频域回到时域,即从傅里叶变换的结果重建原始图像。

1.4.1 傅里叶逆变换原理

傅里叶逆变换用于将图像从频域转回到时域。在频域中进行图像处理后,通过傅里叶逆变换,我们可以得到经过处理后的图像。傅里叶逆变换的过程实际上是对傅里叶变换结果进行反向变换的过程。

1.4.2 傅里叶逆变换公式

傅里叶逆变换的一维形式为:

x ( n ) = 1 N ∑ k = 0 N − 1 X ( k ) e j 2 π N k n x(n) = \frac{1}{N} \sum_{k=0}^{N-1} X(k) e^{j\frac{2\pi}{N}kn} x(n)=N1k=0N1X(k)ejN2πkn

对于二维图像,傅里叶逆变换的公式为:

x ( x , y ) = 1 M N ∑ u = 0 M − 1 ∑ v = 0 N − 1 X ( u , v ) e j 2 π M u x e j 2 π N v y x(x, y) = \frac{1}{MN} \sum_{u=0}^{M-1}\sum_{v=0}^{N-1} X(u, v) e^{j\frac{2\pi}{M}ux}e^{j\frac{2\pi}{N}vy} x(x,y)=MN1u=0M1v=0N1X(u,v)ejM2πuxejN2πvy

其中, X ( u , v ) X(u, v) X(u,v) 是傅里叶变换的结果。

1.4.3 代码实现

在OpenCV中,可以使用 cv2.idft 函数进行傅里叶逆变换。以下是一个简单的例子:

import cv2
import numpy as np

# 读取图像
img = cv2.imread('tulips.jpg', 0)

# 进行傅里叶变换
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)

# 将变换后图像的低频部分转移到图像的中心
dft_shift = np.fft.fftshift(dft)

# 定义掩模:生成的掩模中间为1周围为0
center_y, center_x = int(img.shape[0] / 2), int(img.shape[1] / 2)  # 求得图像的中心点位置
mask = np.zeros((img.shape[0], img.shape[1], 2), np.uint8)
mask[center_y - 50:center_y + 50, center_x - 50:center_x + 50] = 1
reversed_mask = 1 - mask

# 将掩模与傅里叶变化后图像相乘,保留中间部分
mask_img = dft_shift * mask
# 将掩模与傅里叶变化后图像相乘,保留中间部分
reversed_mask_img = dft_shift * reversed_mask

# 显示频谱图像
magnitude_spectrum = cv2.magnitude(mask_img[:, :, 0], mask_img[:, :, 1])
magnitude_spectrum = np.log(magnitude_spectrum + 1)  # 对数变换增强显示
# 将结果标准化到0~255
magnitude_spectrum_normalized = cv2.normalize(magnitude_spectrum, None, 0, 255, cv2.NORM_MINMAX)
# 进行逆傅里叶变换
idft = cv2.idft(np.fft.ifftshift(mask_img))
idft = cv2.magnitude(idft[:, :, 0], idft[:, :, 1])
# 将结果标准化到0~255
idft_normalized = cv2.normalize(idft, None, 0, 255, cv2.NORM_MINMAX)

# 显示频谱图像
reversed_magnitude_spectrum = cv2.magnitude(reversed_mask_img[:, :, 0], reversed_mask_img[:, :, 1])
reversed_magnitude_spectrum = np.log(reversed_magnitude_spectrum + 1)  # 对数变换增强显示
# 将结果标准化到0~255
reversed_magnitude_spectrum_normalized = cv2.normalize(reversed_magnitude_spectrum, None, 0, 255, cv2.NORM_MINMAX)
# 进行逆傅里叶变换
reversed_idft = cv2.idft(np.fft.ifftshift(reversed_mask_img))
reversed_idft = cv2.magnitude(reversed_idft[:, :, 0], reversed_idft[:, :, 1])

# 将结果标准化到0~255
reversed_idft_normalized = cv2.normalize(reversed_idft, None, 0, 255, cv2.NORM_MINMAX)

# 显示原始图像和标准化后的逆傅里叶变换结果
cv2.imshow('Inverse Fourier Transform',
           cv2.vconcat([
               cv2.hconcat([mask[:, :, 0] * 255, np.uint8(magnitude_spectrum_normalized), np.uint8(idft_normalized)]),
               cv2.hconcat([reversed_mask[:, :, 0] * 255, np.uint8(reversed_magnitude_spectrum_normalized),
                            np.uint8(reversed_idft_normalized)])
           ]))
cv2.waitKey(0)
cv2.destroyAllWindows()

Inverse Fourier Transform
这段代码主要执行了以下操作:

  1. 读取名为 ‘tulips.jpg’ 的图像,并将其转换为灰度图像。
  2. 对图像进行傅里叶变换,将时域信号转换为频域信号。这涉及到使用 cv2.dft 函数来计算傅里叶变换,并通过 np.fft.fftshift 将频谱中的低频部分移到中心。
  3. 定义两个掩模(mask):
    • mask: 中间部分为1,周围为0,用于保留图像中心的频率信息。
    • reversed_mask: 与 mask 相反,中间部分为0,周围为1,用于保留图像边缘的频率信息。
  4. 将定义的掩模与傅里叶变换后的图像相乘,以保留或排除中间频率部分。
  5. 计算两个不同掩模条件下的频谱图像,并对其进行对数变换,以增强显示。
  6. 对通过掩模保留的频域信号进行逆傅里叶变换,将频域信号转换回时域。
  7. 将结果标准化到0~255,以便在图像中正确显示。

在展示的图像中,上半部分显示了通过中心掩模保留的频率信息,下半部分显示了通过反向掩模排除的频率信息。这种操作可以用于图像的频域分析和滤波。在实际应用中,傅里叶逆变换常用于图像重建和修复等任务。

二、积分图像

2.1 积分图像原理

积分图像是一种高效的数据结构,用于快速计算图像区域的像素和,特别是在进行图像分析和处理时。

标准求和积分

标准求和积分图像是最基础的形式,它计算原始图像中每个位置及其左上方所有像素的累积和。具体来说,对于图像中的每个像素位置 (x, y),积分图像 I(x, y) 表示的是原始图像 O(x', y') 在区域 (0, 0)(x, y) 之间的所有像素和。

计算公式:
I ( x , y ) = ∑ x ′ < x , y ′ < y O ( x ′ , y ′ ) I(x, y) = \sum_{x' < x, y' < y} O(x', y') I(x,y)=x<x,y<yO(x,y)

平方和积分

平方和积分图像不仅计算像素的累积和,而且还计算每个像素值的平方的累积和。这对于计算图像的局部方差和标准差特别有用。

计算公式:
I s q ( x , y ) = ∑ x ′ < x , y ′ < y O ( x ′ , y ′ ) 2 I_{sq}(x, y) = \sum_{x' < x, y' < y} O(x', y')^2 Isq(x,y)=x<x,y<yO(x,y)2

倾斜求和积分

倾斜求和积分图像计算的是图像中沿着某一角度(通常是45度)的倾斜区域的像素和。这种类型的积分图像在处理如斜线特征检测或倾斜矩形区域的和时特别有用。它的核心思想是沿着倾斜方向累积像素值,从而能够快速计算任意倾斜矩形区域内的像素和。

倾斜求和积分的计算公式稍微复杂一些,涉及到对图像的斜向遍历。对于图像中的每个像素 (x, y),倾斜积分图像 I_t(x, y) 表示的是原始图像 O(x', y') 在由 (x, y) 点沿着特定倾斜角(如45度)形成的三角形区域内所有像素的和。

计算公式大致可以表示为:
I t ( x , y ) = ∑ x ′ + y ′ < x + y O ( x ′ , y ′ ) I_t(x, y) = \sum_{x' + y' < x + y} O(x', y') It(x,y)=x+y<x+yO(x,y)

这个公式意味着对于图像中的每个点 (x, y),我们计算从该点沿着倾斜方向到图像左上角的所有像素值的累积和。在实际的编程实现中,这通常需要考虑边界条件和有效的累积方式,以确保计算的准确性和效率。

由于具体的算法实现可能较为复杂,涉及到图像处理和数组操作的高级技巧,这里不进行详细的代码展示。不过,倾斜积分图像的概念和基本原理是理解其应用的关键。

2.2 代码实现

在OpenCV中,可以使用 cv2.integral3 函数来计算图像的积分图像。以下是一个简单的示例代码:

import cv2
import numpy as np

# 读取灰度图像
image = cv2.imread('tulips.jpg', 0)
# 获取图像的高度和宽度
height, width = image.shape

# 创建一个新的图像,高度和宽度各增加一
new_height = height + 1
new_width = width + 1
new_image = np.zeros((new_height, new_width), dtype=np.uint8)
# 将原始图像复制到新图像中
new_image[:height, :width] = image

# 计算积分图像
# 调用integral3计算积分图
sum_integral, sqsum_integral, tilted_integral = cv2.integral3(image)


def process_integral(img_integral):
    # 将积分图像进行归一化,以便在图像显示时保持合适的范围
    normalized_img = cv2.normalize(img_integral, None, 0, 255, cv2.NORM_MINMAX)
    return normalized_img


log_sum_integral = process_integral(sum_integral)
log_sqsum_integral = process_integral(sqsum_integral)
log_tilted_integral = process_integral(tilted_integral)
# 显示原始图像和积分图像
cv2.imshow('Integral Image', cv2.vconcat([
            cv2.hconcat([new_image, np.uint8(log_sum_integral)]),
            cv2.hconcat([np.uint8(log_sqsum_integral), np.uint8(log_tilted_integral)])]))
cv2.waitKey(0)
cv2.destroyAllWindows()

Integral Image

integral, integral2, integral3 都是 OpenCV 库中用于计算图像的积分图的函数,它们的功能各有不同:

  1. integral(src[, sum[, sdepth]]): 这个函数计算单一的积分图像。它接受原始图像 src 作为输入,并返回积分图像sum。积分图像中的每个元素是原始图像中对应位置左上角所有像素的累积和。此函数主要用于快速计算图像区域内的像素和。

  2. integral2(src[, sum[, sqsum[, sdepth[, sqdepth]]]]): 这个函数除了计算标准的积分图 sum 外,还计算了平方和积分图sqsum。平方和积分图用于存储原始图像中每个像素值的平方的累积和,这在计算图像的局部方差和标准差时特别有用。

  3. integral3(src[, sum[, sqsum[, tilted[, sdepth[, sqdepth]]]]]): 这个函数是最全面的,它计算标准积分图 sum、平方和积分图 sqsum,以及倾斜积分图tilted。倾斜积分图像是一种特殊类型的积分图像,它考虑了原始图像沿45度角旋转的像素累积和,这对于某些类型的特征检测特别有用。


总结

本文为读者提供了深入浅出的视角,探索了图像分析的核心技术。

  1. 首先,通过对离散傅里叶变换的原理、公式和代码实现的详细讲解,使读者能够理解如何将图像从空间域转换到频率域。特别是对 cv2.dft函数的解析,增强了对傅里叶变换在实际应用中的理解。
  2. 接着,文中通过讨论傅里叶变换在卷积操作中的应用,及其如何通过cv2.mulSpectrums 函数实现,进一步展示了傅里叶变换在图像处理中的实用性。
  3. 此外,离散余弦变换的介绍和 cv2.dct 函数的分析为读者提供了另一种重要的频域分析工具。
  4. 最后,傅里叶逆变换的部分使读者能够从频率域恢复到空间域,理解整个变换过程的完整性。
  5. 在积分图像部分,文章详细讨论了积分图像的原理和代码实现。

猜你喜欢

转载自blog.csdn.net/qq_31463571/article/details/134548763