图像高通滤波、特征检测、修复、分割及深度估计技术解析
1. 高通滤波器与特征检测
高通滤波器的概念与低通滤波器相反,它允许信息(如信号和图像)的高频分量通过,因此得名。在图像中,边缘属于高频分量,高通滤波器使用的内核会增强图像中的强烈分量,所以对图像应用高通滤波器时,输出结果就是图像的边缘。
OpenCV 提供了许多实现高通滤波器的库函数,下面介绍几个常用函数及其参数:
| 参数 | 含义 |
| ---- | ---- |
| src | 要检测边缘的源图像 |
| ddepth | 决定目标图像的深度,-1 表示源图像和目标图像深度相同 |
| dx | X 方向的导数阶数(Laplacian() 函数不需要) |
| dy | Y 方向的导数阶数(Laplacian() 函数不需要) |
| ksize | 内核矩阵的大小(Sobel() 函数可以是 1、3、5 或 7;Laplacian() 函数是正奇数;Scharr() 函数不需要) |
| scale | 可选的缩放因子,默认不应用缩放 |
| delta | 可选的常数,添加到最终输出 |
| borderType | 边界像素的外推方法 |
以下是使用 Sobel()、Laplacian() 和 Scharr() 函数计算输入图像的拉普拉斯和一阶 X 导数的代码:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('/home/pi/book/dataset/4.1.05.tiff', 0)
laplacian = cv2.Laplacian(img, ddepth=cv2.CV_32F, ksize=17,
scale=1, delta=0,
borderType=cv2.BORDER_DEFAULT)
sobel = cv2.Sobel(img, ddepth=cv2.CV_32F, dx=1, dy=0,
ksize=11, scale=1, delta=0,
borderType=cv2.BORDER_DEFAULT)
scharr = cv2.Scharr(img, ddepth=cv2.CV_32F, dx=1, dy=0,
scale=1, delta=0,
borderType=cv2.BORDER_DEFAULT)
images=[img, laplacian, sobel, scharr]
titles=['Original', 'Laplacian', 'Sobel', 'Scharr']
for i in range(4):
plt.subplot(2, 2, i+1)
plt.imshow(images[i], cmap = 'gray')
plt.title(titles[i])
plt.axis('off')
plt.show()
使用 Laplacian()、Scharr() 和 Sobel() 函数计算图像的 X 导数会返回输入图像中的垂直边缘。
我们还可以连接两个按钮到 7 和 11 GPIO 引脚,通过编程调整 dx 和 dy 的值,代码如下:
import RPi.GPIO as GPIO
import cv2
x = 0
y = 1
cap = cv2.VideoCapture(0)
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
button1 = 7
button2 = 11
GPIO.setup(button1, GPIO.IN, GPIO.PUD_UP)
GPIO.setup(button2, GPIO.IN, GPIO.PUD_UP)
while True:
print(x, y)
ret, frame = cap.read()
button1_state = GPIO.input(button1)
if button1_state == GPIO.LOW:
x = 0
y = 1
button2_state = GPIO.input(button2)
if button2_state == GPIO.LOW:
x = 1
y = 0
output = cv2.Scharr(frame, ddepth=cv2.CV_32F,
dx=x, dy=y,
scale=1, delta=0,
borderType=cv2.BORDER_DEFAULT)
cv2.imshow('Salt and pepper Noise App', output)
if cv2.waitKey(1) == 27:
break
cap.release()
cv2.destroyAllWindows()
另外,我们可以将同一实时视频流的 X 导数和 Y 导数(使用 Scharr 计算)相加,代码如下:
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
output1 = cv2.Scharr(frame, ddepth=cv2.CV_32F,
dx=0, dy=1,
scale=1, delta=0,
borderType=cv2.BORDER_DEFAULT)
output2 = cv2.Scharr(frame, ddepth=cv2.CV_32F,
dx=1, dy=0,
scale=1, delta=0,
borderType=cv2.BORDER_DEFAULT)
cv2.imshow('Addition of Vertical and Horizontal',
cv2.add(output1, output2))
if cv2.waitKey(1) == 27:
break
cap.release()
cv2.destroyAllWindows()
2. Canny 边缘检测器
Canny 边缘检测算法由 John Canny 开发,该算法大量使用了高通滤波器的概念,具有多个步骤:
1. 对输入图像应用 5x5 像素的高斯核以去除噪声。
2. 计算滤波后图像强度的梯度,可以使用 L1 或 L2 范数。
3. 应用非极大值抑制,识别可能的边缘候选集。
4. 最后进行滞后阈值处理,根据传递给图像的阈值确定最终的边缘。
OpenCV 的 cv2.Canny() 函数实现了 Canny 算法,其参数如下:
| 参数 | 含义 |
| ---- | ---- |
| img | 需要检测边缘的输入源图像 |
| threshold1 | 阈值的下限 |
| threshold2 | 阈值的上限 |
| L2gradient | 如果为 True,使用 L2 范数计算边缘集,更准确但计算量大;如果为 False,使用 L1 范数计算,计算量小但准确性低 |
以下代码演示了 Canny 边缘检测:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('/home/pi/book/dataset/4.1.05.tiff', 0)
edges1 = cv2.Canny(img, 50, 300, L2gradient=False)
edges2 = cv2.Canny(img, 100, 150, L2gradient=True)
images = [img, edges1, edges2]
titles = ['Original', 'L1 Gradient', 'L2 Gradient']
for i in range(3):
plt.subplot(1, 3, i+1)
plt.imshow(images[i], cmap = 'gray')
plt.title(titles[i])
plt.axis('off')
plt.show()
我们还可以通过 OpenCV 的跟踪条实时调整阈值来计算边缘,代码如下:
import cv2
cv2.namedWindow('Canny')
img = cv2.imread('/home/pi/book/dataset/4.1.05.tiff', 0)
def empty(z):
pass
cv2.createTrackbar('Threshold 1', 'Canny', 50, 100, empty)
cv2.createTrackbar('Threshold 2', 'Canny', 150, 300, empty)
while(True):
l1 = cv2.getTrackbarPos('Threshold 1', 'Canny')
l2 = cv2.getTrackbarPos('Threshold 2', 'Canny')
output = cv2.Canny(img, l1, l2, L2gradient=False)
cv2.imshow('Canny', output)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
3. 霍夫变换检测圆和线
OpenCV 的 cv2.HoughCircles() 函数可以使用霍夫方法检测图像中的圆,它返回检测到的圆的圆心和半径。以下是使用该函数检测 USB 网络摄像头实时视频流中圆的代码:
import cv2
cap = cv2.VideoCapture(0)
while (True):
ret , frame = cap.read()
grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blur = cv2.blur(grey, (5, 5))
circles = cv2.HoughCircles(blur,
method=cv2.HOUGH_GRADIENT,
dp=1, minDist=200,
param1=50, param2=13,
minRadius=30, maxRadius=175)
if circles is not None:
for i in circles [0,:]:
cv2.circle(frame, (i[0], i[1]), i[2], (0, 255, 0), 2)
cv2.circle(frame, (i[0], i[1]), 2, (0, 0, 255), 3)
cv2.imshow('Detected', frame)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
cap.release()
OpenCV 的 cv2.HoughLines() 函数可以检测图像中的线,它接受灰度图像、rho(累加器的距离精度)、theta(累加器的角度精度)和累加器的阈值作为参数。以下是使用该函数检测 USB 网络摄像头实时视频流中线的代码:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 250, apertureSize=5,
L2gradient=True)
lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
if lines is not None:
for rho,theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
pts1 = (int(x0 + 1000*(-b)), int(y0 + 1000*(a)))
pts2 = (int(x0 - 1000*(-b)), int(y0 - 1000*(a)))
cv2.line(img, pts1, pts2, (0, 0, 255), 2)
cv2.imshow('Detected Lines', img)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
cap.release()
4. Harris 角点检测
OpenCV 的 cv2.cornerHarris() 函数用于检测角点,其参数如下:
| 参数 | 含义 |
| ---- | ---- |
| img | 输入图像,必须是灰度图且为 float32 类型 |
| blockSize | 角点检测时考虑的邻域大小 |
| ksize | 使用的 Sobel 导数的孔径参数 |
| k | 方程中使用的自由 Harris 检测器参数 |
以下是实现 Harris 角点检测的示例代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('/home/pi/book/dataset/4.1.05.tiff', 0)
img = np.float32(img)
dst = cv2.cornerHarris(img, 2, 3, 0.04)
ret, dst = cv2.threshold(dst, 0.01*dst.max(), 255, 0)
dst = np.uint8(dst)
plt.imshow(dst, cmap='gray')
plt.axis('off')
plt.show()
5. 图像修复、分割与深度图
图像修复是从图像的现有部分重建受损部分的计算过程。图像可能会因为多种原因受损,如照片纸随时间退化、传感器故障、相机镜头上的灰尘和污垢等。OpenCV 的 cv2.inpaint() 函数实现了两种图像修复方法,该函数接受受损源图像、图像修复掩码、修复邻域大小和修复方法作为参数。
以下是使用两种方法进行图像修复的代码:
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('/home/pi/book/dataset/Damaged.tiff')
mask = cv2.imread('/home/pi/book/dataset/Mask.tiff', 0)
input = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
output_TELEA = cv2.inpaint(input, mask, 5, cv2.INPAINT_TELEA)
output_NS = cv2.inpaint(input, mask, 5, cv2.INPAINT_NS)
plt.subplot(221)
plt.imshow(input)
plt.title('Damaged Image')
plt.axis('off')
plt.subplot(222)
plt.imshow(mask, cmap='gray')
plt.title('Mask')
plt.axis('off')
plt.subplot(223)
plt.imshow(output_TELEA)
plt.title('Telea Method')
plt.axis('off')
plt.subplot(224)
plt.imshow(output_NS)
plt.title('Navier Stokes Method')
plt.axis('off')
plt.show()
图像分割是将图像分成不同区域的过程,阈值处理是一种基本的分割形式。最后,还可以计算视差图并估计图像中物体的深度。
综上所述,这些技术在工业自动化、智能车辆和机器人技术等领域有着广泛的应用。通过掌握这些技术,我们可以对图像进行更深入的处理和分析。
图像高通滤波、特征检测、修复、分割及深度估计技术解析
6. 图像修复、分割与深度图的详细分析
在前面我们已经了解了图像修复的基本概念和使用 OpenCV 的
cv2.inpaint()
函数进行修复的方法。下面我们进一步分析图像修复的两种方法及其应用场景。
- Telea 方法 :基于 2004 年 Alexandru Telea 发表的论文中描述的技术。该方法在处理一些纹理较为简单、连续性较好的图像损伤时效果较好,能够快速且有效地填充受损区域,使修复后的图像在视觉上较为自然。
- Navier - Stokes 方法 :基于 2001 年 Bertalmio Marcelo、Andrea L. Bertozzi 和 Guillermo Sapiro 发表的论文中描述的技术。这种方法在处理复杂纹理和具有一定结构的图像损伤时表现出色,它能够更好地保留图像的原有结构和纹理信息。
以下是这两种方法的对比表格:
| 方法 | 原理依据 | 适用场景 | 优点 |
| ---- | ---- | ---- | ---- |
| Telea 方法 | An Image Inpainting Technique Based on the Fast Marching Method | 纹理简单、连续性好的图像损伤 | 修复速度快,视觉效果自然 |
| Navier - Stokes 方法 | Navier - Stokes, Fluid Dynamics, and Image and Video Inpainting | 复杂纹理和有结构的图像损伤 | 更好地保留图像结构和纹理信息 |
图像分割是将图像划分成不同区域的过程,它在许多领域都有重要应用,如目标检测、图像识别等。常见的图像分割方法有以下几种:
1.
阈值分割
:这是最基本的分割方法,通过设定一个或多个阈值,将图像像素分为不同的类别。例如,对于灰度图像,可以根据像素的灰度值与阈值的比较结果,将像素分为前景和背景。
2.
基于边缘的分割
:利用图像中的边缘信息进行分割。边缘通常对应着图像中不同区域的边界,通过检测边缘可以将图像分割成不同的部分。前面介绍的 Canny 边缘检测算法就可以用于基于边缘的分割。
3.
基于区域的分割
:根据图像中像素的相似性(如颜色、纹理等)将图像划分为不同的区域。常见的方法有区域生长、分水岭算法等。
下面是一个简单的阈值分割示例代码:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('/home/pi/book/dataset/4.1.05.tiff', 0)
ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
plt.imshow(thresh, cmap='gray')
plt.axis('off')
plt.show()
深度估计是计算机视觉中的一个重要任务,它可以帮助我们了解图像中物体的三维信息。通过计算视差图可以实现深度估计,视差图反映了左右图像中对应点的水平位移差异。一般来说,视差越大,物体离相机越近。
7. 技术应用流程总结
为了更清晰地展示这些技术的应用流程,我们可以使用 mermaid 流程图来表示。以下是一个综合的图像特征检测、修复、分割及深度估计的流程图:
graph LR
A[输入图像] --> B{选择处理类型}
B --> |特征检测| C[高通滤波]
B --> |图像修复| D[选择修复方法]
B --> |图像分割| E[选择分割方法]
B --> |深度估计| F[计算视差图]
C --> G[边缘检测(Canny 等)]
C --> H[角点检测(Harris 等)]
C --> I[圆和线检测(霍夫变换)]
D --> J[Telea 方法]
D --> K[Navier - Stokes 方法]
E --> L[阈值分割]
E --> M[基于边缘的分割]
E --> N[基于区域的分割]
F --> O[获取深度信息]
G --> P[输出边缘图像]
H --> Q[输出角点图像]
I --> R[输出圆和线检测结果]
J --> S[输出修复后图像(Telea)]
K --> T[输出修复后图像(Navier - Stokes)]
L --> U[输出分割结果(阈值)]
M --> V[输出分割结果(边缘)]
N --> W[输出分割结果(区域)]
O --> X[输出深度图]
8. 技术优化与拓展
在实际应用中,为了提高这些技术的性能和效果,我们可以进行一些优化和拓展。
-
参数调整
:对于高通滤波、Canny 边缘检测、霍夫变换等算法,合理调整参数可以显著提高检测效果。例如,在霍夫变换检测圆时,可以根据实际情况调整
minDist
、
param1
、
param2
等参数,以减少误检和漏检。
-
多算法结合
:将不同的算法结合使用可以发挥各自的优势。例如,在图像分割中,可以先使用 Canny 边缘检测得到边缘信息,再结合区域生长算法进行更精确的分割。
-
深度学习方法
:近年来,深度学习在计算机视觉领域取得了巨大的成功。可以使用深度学习模型进行图像修复、分割和特征检测,如 U - Net 用于图像分割,Pix2Pix 用于图像修复等。
以下是一个简单的参数调整示例,以霍夫变换检测圆为例:
import cv2
cap = cv2.VideoCapture(0)
while (True):
ret, frame = cap.read()
grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blur = cv2.blur(grey, (5, 5))
# 调整参数
circles = cv2.HoughCircles(blur,
method=cv2.HOUGH_GRADIENT,
dp=1, minDist=150,
param1=60, param2=15,
minRadius=20, maxRadius=200)
if circles is not None:
for i in circles[0, :]:
cv2.circle(frame, (i[0], i[1]), i[2], (0, 255, 0), 2)
cv2.circle(frame, (i[0], i[1]), 2, (0, 0, 255), 3)
cv2.imshow('Detected', frame)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
cap.release()
9. 总结
通过对图像高通滤波、特征检测、修复、分割及深度估计技术的详细介绍,我们了解了这些技术的原理、实现方法和应用场景。高通滤波和特征检测可以帮助我们提取图像中的重要特征,如图像边缘、角点、圆和线等;图像修复技术可以恢复受损图像的质量;图像分割可以将图像划分为不同的区域,便于后续的分析和处理;深度估计可以让我们获取图像中物体的三维信息。
这些技术在工业自动化、智能车辆、机器人技术、医学图像分析等领域都有广泛的应用前景。在实际应用中,我们需要根据具体需求选择合适的算法和方法,并进行必要的优化和拓展,以达到最佳的处理效果。
超级会员免费看
1261

被折叠的 条评论
为什么被折叠?



