Python OpenCV图像处理与深度学习:Python OpenCV边缘检测入门
边缘检测:探索图像的轮廓
学习目标
通过本课程,学员们将掌握使用OpenCV进行边缘检测的基本方法,特别是Canny边缘检测算法的原理及其在Python中的实现。实验将通过理论讲解与实践操作相结合的方式,帮助学员理解边缘检测在图像处理中的重要性,并能够独立完成简单的边缘检测任务。
相关知识点
- Python OpenCV边缘检测
学习内容
1 Python OpenCV边缘检测
1.1 图像边缘检测的基本概念
图像边缘检测是图像处理和计算机视觉中的一个基本问题,它旨在从图像中提取出物体的轮廓信息。边缘通常定义为图像中亮度发生急剧变化的区域,这些变化可能是由于颜色、纹理或深度的不连续性引起的。边缘检测在许多应用中都非常重要,例如图像分割、特征提取、物体识别等。
边缘检测的基本原理是通过检测图像中像素值的梯度来识别边缘。梯度是一个向量,它指向函数值增加最快的方向,其大小表示变化的速率。在图像处理中,通常使用一阶导数(梯度)或二阶导数(拉普拉斯算子)来检测边缘。一阶导数检测边缘的位置,而二阶导数则可以用来确定边缘的精确位置。
1.2 Canny边缘检测算法原理
Canny边缘检测算法是John Canny在1986年提出的一种多级边缘检测算法,它被认为是边缘检测的“黄金标准”。Canny算法的目标是找到一个最优的边缘检测方法,该方法应该满足三个主要标准:好的检测、好的定位和唯一的响应。
- 好的检测:算法应该尽可能多地检测到图像中的实际边缘,同时尽量减少误检。
- 好的定位:检测到的边缘应该尽可能接近实际边缘的位置。
- 唯一的响应:算法应该尽量减少对单个边缘的重复检测。
Canny算法的步骤如下:
- 噪声去除:使用高斯滤波器平滑图像,以减少噪声对边缘检测的影响。
- 计算梯度强度和方向:使用Sobel算子计算图像中每个像素点的梯度强度和方向。
- 非极大值抑制:通过非极大值抑制来细化边缘,只保留局部最大值的像素点。
- 双阈值检测:使用两个阈值(高阈值和低阈值)来确定哪些边缘点是真正的边缘点。高于高阈值的点被认为是强边缘点,低于低阈值的点被丢弃,介于两者之间的点如果与强边缘点相连则被保留。
- 边缘跟踪:通过跟踪强边缘点来连接边缘,形成连续的边缘线。
1.3 使用OpenCV实现Canny边缘检测
在本课程中,将通过Python和OpenCV库来实现Canny边缘检测算法。首先,确保已经安装了OpenCV库,如果没有安装,可以使用以下命令进行安装:
%pip install opencv-python
接下来,编写一个简单的Python脚本来实现Canny边缘检测。使用一张示例图像,并逐步展示每个步骤的实现。
1.3.1 读取和显示图像
执行以下指令获取测试图片。
!wget https://model-community-picture.obs.cn-north-4.myhuaweicloud.com/ascend-zone/notebook_datasets/ec8bff622fa911f08e8ffa163edcddae/example.jpg
首先,需要读取一张图像并显示它。这一步骤确认图像已经正确加载。
import cv2
import matplotlib.pyplot as plt
import numpy as np# 读取图像
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)# 显示图像
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.show()
1.3.2 噪声去除
接下来,使用高斯滤波器对图像进行平滑处理,以减少噪声的影响。
# 应用高斯滤波器
blurred_image = cv2.GaussianBlur(image, (5, 5), 0)# 显示平滑后的图像
plt.imshow(blurred_image, cmap='gray')
plt.title('Blurred Image')
plt.show()
1.3.3 计算梯度强度和方向
使用Sobel算子计算图像中每个像素点的梯度强度和方向。
# 计算梯度
sobelx = cv2.Sobel(blurred_image, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(blurred_image, cv2.CV_64F, 0, 1, ksize=3)# 计算梯度强度和方向
gradient_magnitude = cv2.magnitude(sobelx, sobely)
gradient_direction = cv2.phase(sobelx, sobely, angleInDegrees=True)# 显示梯度强度图像
plt.imshow(gradient_magnitude, cmap='gray')
plt.title('Gradient Magnitude')
plt.show()
1.3.4 非极大值抑制
通过非极大值抑制来细化边缘,只保留局部最大值的像素点。
# 非极大值抑制
def non_max_suppression(gradient_magnitude, gradient_direction):height, width = gradient_magnitude.shapesuppressed = gradient_magnitude.copy()for i in range(1, height - 1):for j in range(1, width - 1):angle = gradient_direction[i, j]if (0 <= angle < 22.5) or (157.5 <= angle <= 180):q = gradient_magnitude[i, j + 1]r = gradient_magnitude[i, j - 1]elif (22.5 <= angle < 67.5):q = gradient_magnitude[i + 1, j - 1]r = gradient_magnitude[i - 1, j + 1]elif (67.5 <= angle < 112.5):q = gradient_magnitude[i + 1, j]r = gradient_magnitude[i - 1, j]else:q = gradient_magnitude[i - 1, j - 1]r = gradient_magnitude[i + 1, j + 1]if gradient_magnitude[i, j] < max(q, r):suppressed[i, j] = 0return suppressedsuppressed_image = non_max_suppression(gradient_magnitude, gradient_direction)
# 显示非极大值抑制后的图像
plt.imshow(suppressed_image, cmap='gray')
plt.title('Non-Max Suppression')
plt.show()
1.3.5 双阈值检测
使用两个阈值(高阈值和低阈值)来确定哪些边缘点是真正的边缘点。
# 双阈值检测
def double_threshold(suppressed, low_threshold, high_threshold):strong_edge = 255weak_edge = 50thresholded = suppressed.copy()strong_i, strong_j = np.where(thresholded >= high_threshold)weak_i, weak_j = np.where((thresholded <= high_threshold) & (thresholded >= low_threshold))thresholded[strong_i, strong_j] = strong_edgethresholded[weak_i, weak_j] = weak_edgethresholded[thresholded < low_threshold] = 0return thresholdedthresholded_image = double_threshold(suppressed_image, 50, 150)
# 显示双阈值检测后的图像
plt.imshow(thresholded_image, cmap='gray')
plt.title('Double Threshold')
plt.show()
1.3.6 边缘跟踪
通过跟踪强边缘点来连接边缘,形成连续的边缘线。
# 边缘跟踪
def edge_tracking(thresholded):strong_edge = 255weak_edge = 50edges = thresholded.copy()for i in range(1, edges.shape[0] - 1):for j in range(1, edges.shape[1] - 1):if edges[i, j] == weak_edge:if (edges[i + 1, j - 1] == strong_edge oredges[i + 1, j] == strong_edge oredges[i + 1, j + 1] == strong_edge oredges[i, j - 1] == strong_edge oredges[i, j + 1] == strong_edge oredges[i - 1, j - 1] == strong_edge oredges[i - 1, j] == strong_edge oredges[i - 1, j + 1] == strong_edge):edges[i, j] = strong_edgeelse:edges[i, j] = 0return edgesfinal_edges = edge_tracking(thresholded_image)
# 显示最终的边缘检测结果
plt.imshow(final_edges, cmap='gray')
plt.title('Final Edges')
plt.show()