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

文章目录

  • 前言
  • 一、傅里叶变换
    • 1.1 离散傅里叶变换
      • 1.1.1 离散傅里叶变换原理
      • 1.1.2 离散傅里叶变换公式
      • 1.1.3 代码实现
      • 1.1.4 cv2.dft 函数解析
    • 1.2 傅里叶变换进行卷积
      • 1.2.1 傅里叶变换卷积原理
      • 1.2.2 傅里叶变换卷积公式
      • 1.2.3 代码实现
      • 1.2.4 cv2.mulSpectrums 函数解析
    • 1.3 离散余弦变换
      • 1.3.1 离散余弦变换原理
      • 1.3.2 离散余弦变换公式
      • 1.3.3 代码实现
      • 1.3.4 cv2.dct函数解析
    • 1.4 傅里叶逆变换
      • 1.4.1 傅里叶逆变换原理
      • 1.4.2 傅里叶逆变换公式
      • 1.4.3 代码实现
  • 二、积分图像
    • 2.1 积分图像原理
    • 2.2 代码实现
  • 总结


前言

在当今数字时代,图像无处不在,而图像分析成为解读、理解和处理这些图像的关键技术之一。本文将介绍图像分析的基础知识,并结合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. 在积分图像部分,文章详细讨论了积分图像的原理和代码实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/183323.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity机器学习 ML-Agents第一个例子

上一节我们安装了机器学习mlagents的开发环境&#xff0c;本节我们创建第一个例子&#xff0c;了解什么是机器学习。 我们的例子很简单&#xff0c;就是让机器人自主移动到目标位置&#xff0c;不能移动到地板范围外。 首先我们来简单的了解以下机器学习的过程。 机器学习的过…

读像火箭科学家一样思考笔记07_探月思维

1. 挑战“不可能”的科学与企业 1.1. 互联网 1.1.1. 和电网一样具有革命性&#xff0c;一旦你插上电源&#xff0c;就能让自己的生活充满活力 1.1.2. 互联网的接入可以帮助人们摆脱贫困&#xff0c;拯救生命 1.1.3. 互联网还可以提供与天气相关的信息 1.2. 用廉价、可靠的…

搭配:基于OpenCV的边缘检测实战

引言 计算机中的目标检测与人类识别物体的方式相似。作为人类&#xff0c;我们可以分辨出狗的形象&#xff0c;因为狗的特征是独特的。尾巴、形状、鼻子、舌头等特征综合在一起&#xff0c;帮助我们把狗和牛区分开来。 同样&#xff0c;计算机能够通过检测与估计物体的结构和性…

【Django使用】10大章31模块md文档,第5篇:Django模板和数据库使用

当你考虑开发现代化、高效且可扩展的网站和Web应用时&#xff0c;Django是一个强大的选择。Django是一个流行的开源Python Web框架&#xff0c;它提供了一个坚实的基础&#xff0c;帮助开发者快速构建功能丰富且高度定制的Web应用 全套Django笔记直接地址&#xff1a; 请移步这…

【Docker】从零开始:8.Docker命令:Commit提交命令

【Docker】从零开始&#xff1a;8.Docker命令:Commit命令 基本概念镜像镜像分层什么是镜像分层为什么 Docker 镜像要采用这种分层结构 本章要点commit 命令命令格式docker commit 操作参数实例演示1.下载一个新的ubuntu镜像2.运行容器3.查看并安装vim4.退出容器5提交自己的镜像…

51单片机应用从零开始(八)·循环语句(for循环、while 语句、do‐while 语句)

51单片机应用从零开始&#xff08;七&#xff09;循环语句&#xff08;if语句&#xff0c;swtich语句&#xff09;-CSDN博客 目录 1. 用for 语句控制蜂鸣器鸣笛次数 2. 用while 语句控制 LED 3. 用 do‐while 语句控制 P0 口 8 位 LED 流水点亮 1. 用for 语句控制蜂鸣器鸣笛…

009 OpenCV 二值化 threshold

一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、二值化算法 2.1、概述 在机器视觉应用中&#xff0c;OpenCV的二值化函数threshold具有不可忽视的作用。主要的功能是将一幅灰度图进行二值化处理&#xff0c;以此大幅降低图像的数…

Linux:文件系统初步理解

文章目录 文件的初步理解C语言中对文件的接口系统调用的接口位图的理解open调用接口 文件和进程的关系进程和文件的低耦合 如何理解一切皆文件&#xff1f; 本篇总结的是关于Linux中文件的各种知识 文件的初步理解 在前面的文章中有两个观点&#xff0c;1. 文件 内容 属性&…

手撕A*算法(详解A*算法)

A*算法原理 全局路径规划算法&#xff0c;根据给定的起点和终点在全局地图上进行总体路径规划。 导航中使用A*算法计算出机器人到目标位置的最优路线&#xff0c;一般作为规划的参考路线 // 定义地图上的点 struct Point {int x,y; // 栅格行列Point(int x, int y):x(x),y(y){…

51单片机利用I/O口高阻状态实现触摸控制LED灯

51单片机利用I/O口高阻状态实现触摸控制LED灯 1.概述 这篇文章介绍使用I/O口的高阻状态实现一个触摸控制LED灯亮灭的实验。该实验通过手触摸P3.7引脚&#xff0c;改变电平信号控制灯的亮灭。 2.实验过程 2.1.实验材料 名称型号数量单片机STC12C20521LED彩灯无1晶振12MHZ1电…

PDF 批量处理软件BatchOutput PDF mac中文版介绍

BatchOutput PDF mac是一款适用于 Mac 的 PDF 批量处理软件。它可以帮助用户将多个 PDF 文件进行异步处理&#xff0c;提高工作效率。 BatchOutput PDF 可以自动化执行许多任务&#xff0c;包括 PDF 文件的打印、转换、分割、压缩、加密、重命名等&#xff0c;而且它还可以将自…

开启数据库审计(db,extended级别或os级别),并将审计文件存放到/home/oracle/audit下

文章目录 开启数据库审计&#xff08;db,extended级别或os级别&#xff09;&#xff0c;并将审计文件存放到/home/oracle/audit下一. 简介二. 配置2.1. 审计是否安装2.2. 审计表空间迁移2.3. 审计参数2.4. 审计级别2.5. 其他审计选项2.6. 审计相关视图 三. 使用3.1. 开启/关闭审…

案例023:基于微信小程序的童装商城的设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

wpf使用CefSharp.OffScreen模拟网页登录,并获取身份cookie,C#后台执行js

目录 框架信息&#xff1a;MainWindow.xamlMainWindow.xaml.cs爬取逻辑模拟登录拦截请求Cookie获取 CookieVisitorHandle 框架信息&#xff1a; CefSharp.OffScreen.NETCore 119.1.20 MainWindow.xaml <Window x:Class"Wpf_CHZC_Img_Identy_ApiDataGet.MainWindow&qu…

关于前端上传

类似于 上面的传参form-data形式&#xff0c;第一个参数为上传的文件&#xff0c;第二个参数为json格式

Centos部署GitLab-备份恢复

1. 下载rpm包 wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-10.8.4-ce.0.el7.x86_64.rpm2. 安装依赖 yum -y install policycoreutils openssh-server openssh-clients postfix policycoreutils-python3. rpm安装 rpm -ivh gitlab-ce-10.8.4-ce.…

OpenStack云计算平台

目录 一、OpenStack 1、简介 2、硬件需求 3、网络 二、环境搭建 1、安全 2、主机网络 3、网络时间协议(NTP) 4、OpenStack包 5、SQL数据库 6、消息队列 7、Memcached 一、OpenStack 1、简介 官网&#xff1a;https://docs.openstack.org/2023.2/ OpenStack系统由…

git查看某个commit属于哪个分支方法(如何查看commit属于哪个分支)

有时候&#xff0c;当我们由于业务需求很多时&#xff0c;基于同一个分支新建的项目分支也会很多。 在某个时间节点&#xff0c;我们需要合并部分功能点时&#xff0c;我们会忘了这个分支是否已经合入哪个功能点&#xff0c;我们就会查看所有的commit记录&#xff0c;当我们找到…

Jmeter快速入门

文章目录 1.安装Jmeter1.1.下载1.2.解压1.3.运行 2.快速入门2.1.设置中文语言2.2.基本用法 1.安装Jmeter Jmeter依赖于JDK&#xff0c;所以必须确保当前计算机上已经安装了JDK&#xff0c;并且配置了环境变量。 1.1.下载 可以Apache Jmeter官网下载&#xff0c;地址&#xf…

Word中如何实现 图片 | 表格 自动编号与文中引用编号对应

当我们在进行大篇幅word文档的编写时&#xff0c;为了节约修改文章中图片或表格所花费的大量时间&#xff0c;可以将图片自动编号&#xff0c;且让文中引用的顺序跟着图片顺序的变化而变化&#xff0c;具体操作如下&#xff1a; 1. 将鼠标定位在图片或者表格欲加编号的下方或上…