Contents

OpenCV

安装

pip install opencv-python==3.4.2.16

pip install opencv-contrib-python==3.4.2.16

contrib版本提供了额外的扩展功能

module ‘cv2.cv2’ has no attribute ‘xfeatures2d’ 错误解决

Imread flags

-1 unchanged

0 gray

1 color (default)

OpenCV: Flags used for image file reading and writing

https://docs.opencv.org/

imread/imwrite

1
2
gray(bayer) -1,0
color -1,1,default

cv2.imwrite()不会自动创建未有的文件夹,并不会报错!

创建图像

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import cv2
import numpy as np

# 创建一个全黑图像(256x256,3 个通道)
black_image = np.zeros((256, 256, 3), dtype=np.uint8)

# 使用 OpenCV 显示图像
cv2.imshow('Black Image', black_image)
cv2.waitKey(0)  # 等待用户按下任意键关闭窗口
cv2.destroyAllWindows()

显示图像

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

import numpy as np
import matplotlib.pyplot as plt
import cv2
from PIL import Image

# 1、**matplotlib**
plt.imshow(img[..., ::-1])  # RGB模式
# img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 将 BGR 转换为 RGB
plt.axis('off')  # 关闭坐标轴显示
plt.show()

# 2、使用 OpenCV 显示图像
cv2.imshow('Black Image', img)
cv2.waitKey(0)  # 等待用户按下任意键关闭窗口
cv2.destroyAllWindows()

# 3、使用 PIL 显示图像
image = Image.fromarray(img)
image.show()
  • matplotlib: 适合在交互式数据分析和可视化时使用,方便与其他图像和绘图结合。
  • OpenCV: 强大的图像处理功能,适合计算机视觉任务。
  • PIL (Pillow): 简单轻量,适合图像转换和基本显示。

基础绘图

Python 用 OpenCV 画点和圆 (2)_python在图片上画点_星海流萤(AlanWang)的博客-CSDN博客

利用 opencv 里自带的 circle() 函数可以绘制以一个点为圆心特定半径的圆,其函数的声明如下:

cv2.circle(img, center, radius, color[, thickness[, lineType[, shift]]])
1
函数参数含义如下:

img:要画的圆所在的矩形或图像
center:圆心坐标,如 (100, 100)
radius:半径,如 10
color:圆边框颜色,如 (0, 0, 255) 红色,BGR
thickness:正值表示圆边框宽度. 负值表示画一个填充圆形
lineType:圆边框线型,可为 0,4,8
shift:圆心坐标和半径的小数点位数

边缘检测

OpenCV—python 边缘检测(Canny)_SongpingWang的博客-CSDN博客

[Canny]边缘检测 - image processing

canny = cv2.Canny(gray, 10, 30) # 常用1:2 或 1:3

  • 低阈值固定,高阈值越高,细节越少
  • 高阈值固定,低阈值越低,细节越多

形状检测

OpenCV-Python 霍夫直线检测-HoughLinesP函数参数_cv2.houghlinesp参数-CSDN博客

blog.51cto.com

连通域提取

二值图像的连通域标记

OpenCV3学习(9.2)连通域分析函数详解connectedComponents()和connectedComponentsWithStats()_cv::connectedcomponents-CSDN博客

opencv使用起来更方便,返回值信息全面

区域分割

前景物体分割是计算机视觉领域中的一个重要任务,旨在将图像中的前景对象与背景分离。以下是一些常见的前景物体分割算法:

  1. 基于阈值的分割:这是最简单的分割方法之一,通过设置合适的阈值将图像分成前景和背景。适用于前景对象与背景之间的对比度较高的情况。
  2. 基于边缘检测的分割:通过检测图像中的边缘来找到前景对象的边界。常用的边缘检测算法包括 Canny 边缘检测、Sobel 算子等。
  3. 基于区域的分割:将图像分成不同的区域,并根据区域之间的特征来判断哪些区域属于前景。常用的区域分割算法包括分水岭算法、区域增长算法等。
  4. 基于深度学习的分割:使用深度学习方法来训练模型,从而实现对前景对象的准确分割。常用的深度学习模型包括 U-Net、Mask R-CNN 等。
  5. 基于运动的分割:如果图像是视频序列,可以利用帧与帧之间的运动信息来进行前景分割。常用的方法包括基于光流的方法、基于背景建模的方法等。
  6. 基于图割的分割:将图像分成多个区域,并通过最小割最大流算法来找到前景对象的边界。常用的图割算法包括 Boykov-Kolmogorov 算法等。grabcut 交互式前景分割 grabcut++
  7. 基于轮廓的分割:通过检测图像中的轮廓来找到前景对象的边界。常用的轮廓检测算法包括基于边缘检测的方法、基于分水岭算法的方法等。

这些算法可以单独使用,也可以结合使用,根据具体的图像特性和需求选择合适的方法。在实际应用中,通常需要根据具体情况来调整参数和算法,以获得最佳的分割效果。

形态学处理

不同形状的核在形态学操作中具有不同的影响和特点,因此在选择核时需要考虑图像的特点以及所需的操作效果。以下是不同核形状的选取规则和具体区别:

  1. 矩形核(cv2.MORPH_RECT):
    • 特点:矩形核是最常用的形态学核之一,其在腐蚀和膨胀等操作中可以沿着水平和垂直方向分别对图像进行操作。
    • 适用场景:适用于对图像中的细长结构进行处理,例如细小的噪声点或者细线条。
  2. 十字形核(cv2.MORPH_CROSS):
    • 特点:十字形核与矩形核类似,但是它的中心像素为 1,周围的像素为 0,因此在一些情况下可以更强力地改变图像的结构。
    • 适用场景:适用于对图像中的较粗线条或者边缘进行处理。
  3. 椭圆形核(cv2.MORPH_ELLIPSE):
    • 特点:椭圆形核的特点是在腐蚀和膨胀操作中可以沿着任意方向改变图像的结构,因此可以更加灵活地适应图像的形状。
    • 适用场景:适用于对图像中的圆形或者曲线结构进行处理,例如去除边缘或者弯曲部分的噪声。

OpenCV图像处理-平滑处理、形态学操作

OpenCV 理解腐蚀与膨胀(开、闭运算以及形态学方法)_opencv腐蚀膨胀__久夏青的博客-CSDN博客

/posts/opencv/%E8%85%90%E8%9A%80%E8%86%A8%E8%83%80.png

二值化

python实现图像二值化 - 山那边不是山 - 博客园

Python图像的二值化_python二值化图像处理_ljx1400052550的博客-CSDN博客

OpenCV+Python图像二值化

cv2.adaptiveThreshold() 函数用于应用自适应阈值二值化。以下是该函数的参数列表及其说明:

  • src:输入图像,灰度图像(单通道图像)。
  • maxValue:输出图像中的最大像素值。
  • adaptiveMethod:自适应阈值算法的方法。可选参数为:
    • cv2.ADAPTIVE_THRESH_MEAN_C:基于邻域均值的阈值计算。
    • cv2.ADAPTIVE_THRESH_GAUSSIAN_C:基于邻域加权平均的阈值计算。
  • thresholdType:阈值类型。可选参数为:
    • cv2.THRESH_BINARY:大于阈值的像素值设为 maxValue,小于等于阈值的像素值设为 0。
    • cv2.THRESH_BINARY_INV:大于阈值的像素值设为 0,小于等于阈值的像素值设为 maxValue
  • blockSize:局部区域的大小,用于计算阈值。它应该是一个奇数,例如 3、5、7、9 等。
  • C:从局部块中减去的常数。它是一个可选参数,通常为正数或零。

以下是函数的调用格式:

1
2
pythonCopy code
retval, dst = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
  • retval:返回的阈值。
  • dst:输出的二值化图像。

孔洞填充

1、cv2.floodFill

2、findContours + fillPoly

3、形态学重建,连续进行膨胀操作

OpenCV函数应用:基于二值图像的三种孔洞填充方法记录(附python,C++代码)_opencv填充孔洞-CSDN博客

/posts/opencv/floodfill.png

自动选中与种子像素相连的区域,并赋予指定颜色值

opencv 漫水填充算法原理

OpenCV 中的漫水填充算法(Flood Fill Algorithm)是一种基于种子点的区域填充算法,用于填充图像中的连通区域。它从指定的种子点开始,搜索与种子点相邻且具有相似像素值的区域,并将这些像素填充为指定的颜色。

漫水填充算法的原理如下:

  1. 选择种子点: 首先需要选择一个种子点,这个点是填充操作的起始点。
  2. 像素匹配: 从种子点开始,检查当前像素的相邻像素。如果相邻像素的像素值在指定的阈值范围内(可以是灰度值的差异或颜色空间中的差异),则将其标记为填充目标,并继续对其相邻像素进行检查。
  3. 填充: 对于每个相邻像素,如果它的像素值符合条件,则将其标记为填充目标,并继续搜索其相邻像素。这个过程将一直进行下去,直到无法再填充新的像素为止。
  4. 停止条件: 填充操作会在遇到边界或无法满足条件的像素时停止。
  5. 重复填充: 漫水填充算法可以选择性地进行重复填充,以填充多个相邻区域。

在 OpenCV 中,cv2.floodFill() 函数实现了漫水填充算法。该函数接受输入图像、种子点、填充颜色等参数,并根据指定的条件填充图像。通过调整函数的参数,可以实现不同的填充效果,如填充区域的颜色、填充的像素范围等。

如果要使用漫水填充算法填充图像中的多个孔洞,可以通过重复调用 cv2.floodFill() 函数来实现。
每次调用函数时,都需要选择一个不同的种子点,并确保选择的种子点位于不同的孔洞内部。

伪彩色映射

OpenCV – 归一化函数normalize() - 手磨咖啡 - 博客园

1
2
# 拉伸灰度范围
normalized_image = cv2.normalize(gray_image, None, 0, 255, cv2.NORM_MINMAX)

opencv中图像伪彩色处理(C++ / Python) - Anita-ff - 博客园

1
2
3
import cv2 
im_gray = cv2.imread("pluto.jpg", cv2.IMREAD_GRAYSCALE) 
im_color = cv2.applyColorMap(im_gray, cv2.COLORMAP_JET)

resize

opencv —— resize、pyrUp 和 pyrDown 图像金字塔(高斯金字塔、拉普拉斯金字塔)与尺寸缩放(向上采样、向下采样) - 狂奔的小学生 - 博客园

尺寸调整:resize 函数

此函数将源图像精确地转换为指定尺寸地目标图像。如果源图像中设置了 ROI(感兴趣区域),那么 resize() 函数就会对源图像地 ROI 区域进行调整尺寸操作,来输出到目标图像中。若目标图像中已经设置了 ROI 区域,不难理解 resize() 函数将会对源图像进行尺寸调整并填充到目标图像的 ROI 区域中去。

void resize(InputArray src, OutputArray dst, Size dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR);

  • src,输入图像,Mat 类对象即可。
  • dst,输出图像,若其非零时,有着 dsize 的尺寸,或者由 src.size() 计算出来。
  • dsize,输出图像的尺寸。如果它等于零,由如下公式进行计算:

dsize = Size ( round ( fx * src.cols ), round( fy * src.rows ) );

  • fx,延水平轴的缩放系数,有默认值 0,且为 0 时,由下式进行计算:

fx = (double) dsize.width / src.cols

  • fy,延垂直轴的缩放系数,有默认值 0,为 0 时,由下式进行计算:

fy = (double) dsize.height / src.rows

  • interpolation,指定插值方式,默认为 INTER_LINEAR (线性插值)。插值就是根据已知数据点(条件),来预测未知数据点值得方法。在尺寸调整过程中,图像的大小可能发生改变。此时像素与像素之间的关系就不是一一对应关系,因此在尺寸调整过程中,可能会涉及到像素值的插值计算。可选插值方式如下:
    • INTER_NEAREST(最近邻差值)
    • INTER_LINEAR(线性插值,默认)
    • INTER_AREA(区域插值,利用像素区域关系的重采样插值)
    • INTER_CUBIC(三次样条插值,超过 4×4 像素邻域内的双三次插值)
    • INTER_LANCZOS4(Lanczos 插值,超过 8×8 像素邻域的 Lanczos 插值)

若要缩小图像,一般情况下最好用 INTER_AREA 来插值;若要放大图像,一般情况下用 INTER_LINEAR。

opencv —— resize、pyrUp 和 pyrDown 图像金字塔(高斯金字塔、拉普拉斯金字塔)与尺寸缩放(向上采样、向下采样) - 狂奔的小学生 - 博客园

1
2
3
4
resized_image = cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
cv2.resize(img, (w, h) # 指定大小
cv2.resize(gray, None, fx=0.1, fy=0.1) # 指定缩放比例
cv2.resize(base_img, None, fx=4, fy=4, interpolation=cv2.INTER_CUBIC) # 指定插值方法

其中:

  • src:输入图像。
  • dsize:输出图像的大小,可以是一个元组 (width, height),也可以是一个缩放比例的元组 (fx, fy),在这种情况下,输出图像的大小将按照输入图像的大小乘以缩放比例来计算。
  • dst:输出图像,可选参数。
  • fx:水平方向的缩放比例,可选参数。
  • fy:垂直方向的缩放比例,可选参数。
  • interpolation:插值方法,用于调整图像大小。可以是以下值之一:
    • cv2.INTER_NEAREST:最近邻插值。
    • cv2.INTER_LINEAR:双线性插值(默认值)。
    • cv2.INTER_AREA:区域插值。
    • cv2.INTER_CUBIC:双立方插值。
    • cv2.INTER_LANCZOS4:Lanczos插值。

直方图

墨滴社区

通道变换

1
2
img = np.expand_dims(gray, -1).repeat(3, -1) # 单通道转三通道
img = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) 

斑点检测

Opencv之斑点(Blob)检测–SimpleBlobDetector_create

OpenCV-Python系列十二:特征检测(2)–斑点检测

频率域处理

空间域和频率域的转换

图像在空间域和频率域之间的转换通过傅里叶变换和逆傅里叶变换实现。具体步骤如下:

傅里叶变换:将空间域图像转换为频率域表示。二维傅里叶变换用于图像处理:
F(u,v)=∑x=0M−1∑y=0N−1f(x,y)⋅e−j2π(uxM+vyN)
F(u,v)=x=0∑M−1y=0∑N−1f(x,y)⋅e−j2π(Mux+Nvy)

其中,f(x,y)f(x,y) 是空间域图像,F(u,v)F(u,v) 是频率域表示,MM 和 NN 分别是图像的宽度和高度。

逆傅里叶变换:将频率域图像转换回空间域表示:
f(x,y)=1MN∑u=0M−1∑v=0N−1F(u,v)⋅ej2π(uxM+vyN)
f(x,y)=MN1u=0∑M−1v=0∑N−1F(u,v)⋅ej2π(Mux+Nvy)

典型应用
图像去噪:频率域的低通滤波可以去除高频噪声,空间域的中值滤波可以去除椒盐噪声。
图像锐化:频率域的高通滤波可以增强图像边缘,空间域的拉普拉斯滤波也可以达到类似效果。
图像压缩:JPEG压缩通过离散余弦变换(DCT)将图像转换到频率域,保留主要的低频成分进行压缩。

实际示例

以下代码演示了如何对图像进行傅里叶变换,并使用 fftshift 将零频移到中心位置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft2, fftshift

# 创建一个示例图像

image_size = 256
image = np.tile(np.linspace(0, 1, image_size), (image_size, 1))

# 进行二维傅里叶变换

f_transform = fft2(image)
magnitude_spectrum_default = np.log(np.abs(f_transform) + 1)

# 使用 fftshift 将零频移到中心位置

f_transform_shifted = fftshift(f_transform)
magnitude_spectrum_shifted = np.log(np.abs(f_transform_shifted) + 1)

# 显示原始图像、默认频谱图和中心化后的频谱图

fig, ax = plt.subplots(1, 3, figsize=(18, 6))

# 显示原始图像

ax[0].imshow(image, cmap='gray')
ax[0].set_title('原始图像')
ax[0].axis('off')

# 显示默认频谱图(零频在左上角)

ax[1].imshow(magnitude_spectrum_default, cmap='gray')
ax[1].set_title('默认频谱图(零频在左上角)')
ax[1].axis('off')

# 显示中心化后的频谱图(零频在中心)

ax[2].imshow(magnitude_spectrum_shifted, cmap='gray')
ax[2].set_title('中心化频谱图(零频在中心)')
ax[2].axis('off')

# 保存并显示图像

plt.tight_layout()
plt.savefig("/mnt/data/frequency_domain_center_shift.png")
plt.show()

原始图像:显示一个水平梯度的示例图像。
默认频谱图:零频位于左上角。
中心化频谱图:使用 fftshift 后,零频位于中心。

默认频谱图:傅里叶变换后零频位于左上角,这是因为傅里叶变换计算的频率成分按顺序排列,最低频率在开始位置。
中心化频谱图:通过 fftshift 函数将频谱重新排列,使零频位于中心,这样可以更直观地观察和处理频率成分。

默认位置:傅里叶变换后,零频位于左上角。
中心化位置:使用 fftshift 函数后,零频移到频谱图的中心位置。

总结

幅度谱和相位谱是图像傅里叶变换的两个重要组成部分。幅度谱描述频率成分的强度,反映图像的对比度和亮度;
相位谱描述频率成分的相位,反映图像的结构和细节。两者共同构成了图像在频率域中的完整表示,对于图像的分析和处理都非常重要。
理解它们的区别和联系,可以更好地利用频域信息进行图像处理操作。

图像重建

利用频率域谱重建图像需要同时使用幅度谱和相位谱。下面是如何通过频率域信息重建图像的详细步骤,包括数学公式和代码示例。

重建过程

通过频率域的幅度谱和相位谱,可以重建图像,然后使用二维傅里叶逆变换将其转换回空间域。

示例代码

以下是如何使用Python和numpy库进行傅里叶变换、提取幅度谱和相位谱,并重建图像的代码示例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft2, ifft2, fftshift, ifftshift

# 创建一个带有水平梯度的示例图像
image_size = 256
image = np.tile(np.linspace(0, 1, image_size), (image_size, 1))

# 进行二维傅里叶变换
f_transform = fft2(image)
f_transform_shifted = fftshift(f_transform)

# 计算幅度谱和相位谱
magnitude_spectrum = np.abs(f_transform_shifted)
phase_spectrum = np.angle(f_transform_shifted)

# 利用幅度谱和相位谱重建图像
reconstructed_f_transform = magnitude_spectrum * np.exp(1j * phase_spectrum)
reconstructed_f_transform_shifted = ifftshift(reconstructed_f_transform)
reconstructed_image = ifft2(reconstructed_f_transform_shifted)
reconstructed_image = np.abs(reconstructed_image)

# 显示原始图像、幅度谱、相位谱和重建图像
fig, ax = plt.subplots(1, 4, figsize=(24, 6))

# 显示原始图像
ax[0].imshow(image, cmap='gray')
ax[0].set_title('原始图像')
ax[0].axis('off')

# 显示幅度谱
ax[1].imshow(np.log(magnitude_spectrum + 1), cmap='gray')
ax[1].set_title('幅度谱')
ax[1].axis('off')

# 显示相位谱
ax[2].imshow(phase_spectrum, cmap='gray')
ax[2].set_title('相位谱')
ax[2].axis('off')

# 显示重建图像
ax[3].imshow(reconstructed_image, cmap='gray')
ax[3].set_title('重建图像')
ax[3].axis('off')

# 保存并显示图像
plt.tight_layout()
plt.savefig("/mnt/data/reconstructed_image.png")
plt.show()

解释

  1. 原始图像:创建了一个带有水平梯度的示例图像。
  2. 傅里叶变换:对图像进行二维傅里叶变换,得到频率域的表示。
  3. 幅度谱和相位谱:提取频率域的幅度谱和相位谱。
  4. 重建图像:利用幅度谱和相位谱重建频率域表示,然后通过二维傅里叶逆变换重建回空间域图像。

结果图像

  • 原始图像:展示了带有水平梯度的示例图像。
  • 幅度谱:展示了频率成分的强度。
  • 相位谱:展示了频率成分的相位信息。
  • 重建图像:展示了利用频率域信息重建的图像。

关键点

  • 幅度谱和相位谱:幅度谱包含了图像中的频率成分的强度信息,而相位谱包含了这些频率成分的位置信息。
  • 重建图像:同时使用幅度谱和相位谱信息可以完整地重建原始图像。如果只使用其中一个,重建的图像会丢失一些信息。

总结

通过傅里叶变换将图像转换到频率域,可以提取幅度谱和相位谱。利用这两个谱,我们可以通过傅里叶逆变换将频率域信息转换回空间域,重建出原始图像。理解和使用幅度谱和相位谱在图像处理和分析中具有重要的应用。