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

news2024/11/15 9:33:54

文章目录

  • 前言
  • 一、傅里叶变换
    • 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. 在积分图像部分,文章详细讨论了积分图像的原理和代码实现。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LangChain的简单使用介绍

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

解决kubernetes中微服务pod之间调用失败报错connection refused的问题

现象&#xff1a; 从这里可以看到是当前服务在调用product service服务是出现了连接拒绝connection refused 走读一下原始代码&#xff1a; 可以看到请求是由FeignClient代理发出的 &#xff0c;但问题在于为什么Feign请求的时候会产生connection refused错误&#xff1f; 上…

Python+jieba+wordcloud实现文本分词、词频统计、条形图绘制及不同主题的词云图绘制

目录 序言&#xff1a;第三方库及所需材料函数模块介绍分词词频统计条形图绘制词云绘制主函数 效果预览全部代码 序言&#xff1a;第三方库及所需材料 编程语言&#xff1a;Python3.9。 编程环境&#xff1a;Anaconda3&#xff0c;Spyder5。 使用到的主要第三方库&#xff1a;…

飞书+ChatGPT搭建智能AI助手并实现公网访问web界面

文章目录 前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 前言 在飞书中创建chatGPT机器人并且对话&#xff0c;在下面操作步骤中…

时间序列分析算法的概念、模型检验及应用

时间序列分析是一种用于研究随时间变化的数据模式和趋势的统计方法。这类数据通常按照时间顺序排列&#xff0c;例如股票价格、气温、销售额等。时间序列分析的目标是从过去的观测中提取信息&#xff0c;以便预测未来的趋势。 以下是关于时间序列分析的一些重要概念、模型检验…

【深度学习】学习率及多种选择策略

学习率是最影响性能的超参数之一&#xff0c;如果我们只能调整一个超参数&#xff0c;那么最好的选择就是它。相比于其它超参数学习率以一种更加复杂的方式控制着模型的有效容量&#xff0c;当学习率最优时&#xff0c;模型的有效容量最大。本文从手动选择学习率到使用预热机制…

插入排序(形象类比)

最近在看riscv手册的时候&#xff0c;里面有一段代码是插入排序&#xff0c;但是单看代码的时候有点迷&#xff0c;没看懂咋操作的&#xff0c;后来又查资料复习了一下&#xff0c;最终才把代码看明白&#xff0c;所以写篇博客记录一下。 插入排序像打扑克牌 这是我听到过比较形…

RubyMine 2023:提升Rails/Ruby开发效率的强大利器

在Rails/Ruby开发领域&#xff0c;JetBrains RubyMine一直以其强大的功能和优秀的性能而备受开发者的青睐。现如今&#xff0c;我们迎来了全新的RubyMine 2023版本&#xff0c;它将为开发者们带来更高效的开发体验和无可比拟的工具支持。 首先&#xff0c;RubyMine 2023提供了…

IDEA安装教程

文章目录 1 下载IntelliJ IDEA2 安装3 IDEA配置4 创建项目 1 下载IntelliJ IDEA ​ 官方网站上下载最新版本的IntelliJ IDEA。官方网站提供了两个版本&#xff1a;Community版和Ultimate版。 Community版是免费的&#xff0c;适用于个人和非商业用途。Ultimate版则需要付费购…

ESP32之避障

ESP32之避障 图片 程序 int Led27;//定义LED 接口 int buttonpin4; //定义光遮断传感器接口 int val;//定义数字变量val void setup() { pinMode(Led,OUTPUT);//定义LED 为输出接口 pinMode(buttonpin,INPUT);//定义避障传感器为输出接口 } void loop() {Serial.begin(9600);…

JVMj之console Java监视与管理控制台

jconsole Java监视与管理控制台 1、jconsole介绍 jconsole (java monitoring and management console)是一款基于JMX (Java Management Extensions) 的可视化监视和管理工具。 2、启动jconsole 1、在linux和windwos下通过jconsole启动即可。 2、然后会自动搜索本机运行的…

【栈】不同字符的最小子序列

题目&#xff1a; /*** 思路&#xff1a;栈,使用数组记录每个字母出现的次数&#xff0c;再用一个数组标记字符是否在栈中* 遍历栈&#xff0c;存储字符时比较栈顶字符&#xff0c;若小于栈顶字符并且后面有重复的字符则* 栈顶元素出栈&#xff0c;否则入栈。** au…

超级利器!Postman自动化接口测试让你提升测试效率,节省宝贵时间!

Postman自动化接口测试 该篇文章针对已经掌握 Postman 基本用法的读者&#xff0c;即对接口相关概念有一定了解、已经会使用 Postman 进行模拟请求的操作。 当前环境&#xff1a; Window 7 - 64 Postman 版本&#xff08;免费版&#xff09;&#xff1a;Chrome App v5.5.3 …

数字乡村:科技赋能农村产业升级

数字乡村&#xff1a;科技赋能农村产业升级 数字乡村是指通过信息技术和数字化手段&#xff0c;推动农业现代化、农村经济发展和农民增收的一种新模式。近年来&#xff0c;随着互联网技术的飞速发展&#xff0c;数字乡村开始在全国范围内迅速兴起&#xff0c;为乡村经济注入了新…

CVE-2022-0543(Redis 沙盒逃逸漏洞)

简介 CVE-2022-0543是一个与Redis相关的安全漏洞。在Redis中&#xff0c;用户连接后可以通过eval命令执行Lua脚本&#xff0c;但在沙箱环境中脚本无法执行命令或读取文件。然而&#xff0c;攻击者可以利用Lua沙箱中遗留的变量package的loadlib函数来加载动态链接库liblua5.1.s…

tcp/ip协议2实现的插图,数据结构2 (19 - 章)

(68) 68 十九1 选路请求与消息 函rtalloc,rtalloc1,rtfree (69)

解决mv3版本浏览器插件,不能注入js脚本问题

文章目录 背景引入ifream解决ifream和父页面完全跨域问题参考链接 背景 浏览器插件升级mv3版本后&#xff0c;不能再使用content_script内容脚本向原浏览器&#xff08;top&#xff09;注入script标签达到注入脚本的目的。浏览器认为插入未经审核的脚本是不安全的行为。 引入…

从0开始学习JavaScript--JavaScript元编程

JavaScript作为一门灵活的动态语言&#xff0c;具备强大的元编程能力。元编程是一种通过操作程序自身结构的编程方式&#xff0c;使得程序能够在运行时动态地创建、修改、查询自身的结构和行为。本文将深入探讨JavaScript中元编程的各个方面&#xff0c;包括原型、反射、代理等…

揭秘周杰伦《最伟大的作品》MV,绝美UI配色方案竟然藏在这里

色彩在UI设计的基本框架中占据着举足轻重的位置。实际上&#xff0c;精心挑选和组合的色彩配色&#xff0c;往往就是UI设计成功的不二法门。在打造出一个实用的UI配色方案过程中&#xff0c;我们需要有坚实的色彩理论知识&#xff0c;同时还需要擅于从生活中观察和提取灵感。以…

MySQL索引事务基础

目录 1. 索引 1.1索引的概念 1.2索引的特点 1.3 索引的使用场景 1.4索引的使用 1.4.1查看索引 1.4.2创建索引 1.4.3删除索引 1.5索引保存的数据结构 2.事务 2.1经典例子 2.2事务的概念 2.3事务的使用 2.4事务的4个核心特性 2.5事务的并发问题 2.5.1脏读 2.5.2不可…