利用OpenCV进行边缘检测
Posted 卓晴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用OpenCV进行边缘检测相关的知识,希望对你有一定的参考价值。
简 介: 本文讨论了图像处理中重要的技术:边缘检测,重点介绍了两种方法(Sobel边缘检测和Canny边缘检测)。在展示OpenCV中的用法 同时也强调了为什么图像平滑是重要的预处理步骤。在Canny边缘检测中 也是使用的Sobel算子获得导数的数值解。通过应用非最大抑制以及滞回比较, Canny算法更加鲁棒和灵活。这就是为什么Canny算子最令人喜欢并被广泛使用在边缘检测中的原因。
关键词
: 边缘检测,Sobel,Canny
本文是通过 Edge Detection Using OpenCV 中的内容进行整理而成,用于之后的学习和工作。
§00 前 言
边缘检测是图像处理技术,用于确定图片中物体的边界(边缘)或者区域。边缘是图像中重要的特征。我们通过边缘来了解图像的结构信息。边缘检测算法广泛存在于实际应用中的计算机视觉算法处理流水线中。
0.1 如何进行边缘检测?
边缘的特征在于像素亮度的突然变化,为了检测边缘,我们需要能够寻找出存在于相邻像素之间的这种变化。来吧,让我们探讨两种OpenCV中的重要边缘检测算法:Sobel边缘检测以及Canny边缘检测。我们不但演示如何使用OpenCV实现这两个算法,还讨论背后的理论。
首先,看一下将要展示的边缘检测代码。后面会对代码每一行进行讲解帮助你充分理解他们。
- Python
import cv2
# Read the original image
img = cv2.imread('test.jpg')
# Display original image
cv2.imshow('Original', img)
cv2.waitKey(0)
# Convert to graycsale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Blur the image for better edge detection
img_blur = cv2.GaussianBlur(img_gray, (3,3), 0)
# Sobel Edge Detection
sobelx = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=5) # Sobel Edge Detection on the X axis
sobely = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=0, dy=1, ksize=5) # Sobel Edge Detection on the Y axis
sobelxy = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dy=1, ksize=5) # Combined X and Y Sobel Edge Detection
# Display Sobel Edge Detection Images
cv2.imshow('Sobel X', sobelx)
cv2.waitKey(0)
cv2.imshow('Sobel Y', sobely)
cv2.waitKey(0)
cv2.imshow('Sobel X Y using Sobel() function', sobelxy)
cv2.waitKey(0)
# Canny Edge Detection
edges = cv2.Canny(image=img_blur, threshold1=100, threshold2=200) # Canny Edge Detection
# Display Canny Edge Detection Image
cv2.imshow('Canny Edge Detection', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
- C++
#include <opencv2/opencv.hpp>
#include <iostream>
// using namespaces to nullify use of cv::function(); syntax and std::function();
using namespace std;
using namespace cv;
int main()
// Reading image
Mat img = imread("test.jpg");
// Display original image
imshow("original Image", img);
waitKey(0);
// Convert to graycsale
Mat img_gray;
cvtColor(img, img_gray, COLOR_BGR2GRAY);
// Blur the image for better edge detection
Mat img_blur;
GaussianBlur(img_gray, img_blur, Size(3,3), 0);
// Sobel edge detection
Mat sobelx, sobely, sobelxy;
Sobel(img_blur, sobelx, CV_64F, 1, 0, 5);
Sobel(img_blur, sobely, CV_64F, 0, 1, 5);
Sobel(img_blur, sobelxy, CV_64F, 1, 1, 5);
// Display Sobel edge detection images
imshow("Sobel X", sobelx);
waitKey(0);
imshow("Sobel Y", sobely);
waitKey(0);
imshow("Sobel XY using Sobel() function", sobelxy);
waitKey(0);
// Canny edge detection
Mat edges;
Canny(img_blur, edges, 100, 200, 3, false);
// Display canny edge detected image
imshow("Canny edge detection", edges);
waitKey(0);
destroyAllWindows();
return 0;
▲ 图1.1 用于变换检测的图像
在讨论每个算法细节之前,我们需要完成一些变换检测基本步骤。将OpenCV软件库导入,就像下面代码所示:
- Python
import cv2
- C++
#include<opencv2/opencv.hpp>
#include<iostream>
// Namespace nullifies the use of cv::function();
using namespace std;
using namespace cv;
§01 边缘检测
1.1 前期处理
1.1.1 读入图像
第一步使用OpenCV中的imread() 函数将图像读入内存。
这里,我们按照灰度图格式将彩色图片读入内存,这是因为在检测边缘是你不需要彩色信息。如果你想了解读入图片更多参数信息,可以参考 之前的博文 。
1.1.2 图像平滑
载入图像之后,我们也使用 GaussianBlur() 函数对其进行平滑。这是为了去除图片中的噪声。在边缘检测中,需要对像素亮度进行数值求导,结果会产生带有噪声的边缘。换而言之,图像中的相邻像素的亮度(特别是在边缘附近)波动比较大,者会被我们当成边界,但并不是我们寻找的主要边缘结构。
对于边界附近的亮度通过模糊化进行平滑,可以比较容易识别出图像中的主要边缘结构。 你可以通过OpenCV相关文档了解GaussianBlur() 函数的更多的细节。 我们制定卷积核的尺寸(本例中,使用一个3×3的卷积核),决定了模糊化的程度。
- Python
# Read the original image
img = cv2.imread('test.jpg',flags=0)
# Blur the image for better edge detection
img_blur = cv2.GaussianBlur(img,(3,3), SigmaX=0, SigmaY=0)
- C++
// Reading image
Mat img = imread("test.jpg",0);
// Blur the image for better edge detection
Mat img_blur;
GaussianBlur(img, img_blur, Size(3,3), SigmaX=0, SigmaY=0);
1.2 Sobel边缘检测
Sobel变换检测是一个广泛使用的边缘检测算法。 通过下图显示Sobel边缘检算子是寻找那些像素亮度突然变化的边缘。
1.2.1 基本原理
▲ 图1.2.1 像素随着变量t而发生变化
当我们对亮度函数求其一阶导数的时候,会获得更加明显的峰值。
▲ 图1.2.2 求取亮度变化的一阶导数
上面绘制的图像展示了通过检测高于某个阈值的梯度值来检测边缘。再者,导数的突然改变也显示出像素亮度的突变。根据这一点,我们可以使用3×3的卷积核来获得近似导数。 我们使用一个卷积核检测在X方向(水平方向)的像素亮度突变, 使用另外一个卷积核检测Y方向(垂直方向)的亮度突变 。可以通过 这个链接 学习更多关于图像滤波和卷积核的内容。
下面是两个用于Sobel边缘检测的卷积核:
(1)是用于检测X方向边缘的卷积核。
(2)是用于检测Y方向的卷积核。
利用这些卷积核对源图像进行卷积,我们活得“Sobel边缘图像”。
- 如果我们只使用垂直卷积核,卷积结果将会增加X方向边缘;
- 如果使用水平卷积核所获得的的Sobel图像,在Y方向上的边缘被增强;
使用 G x G_x Gx 和 G y G_y Gy 分别代表x和y方向的梯度值,利用A,B表示X,Y方向的卷积核:
G x = A ∗ I , G y = B ∗ I G_x = A * I,\\,\\,\\,G_y = B * I Gx=A∗I,Gy=B∗I
其中 * 表示卷积算子, I I I 表示输入图像。
最终的图像梯度幅值 G G G 可以通过下式计算: G = G x 2 + G y 2 G = \\sqrt G_x^2 + G_y^2 G=Gx2+Gy2
梯度方向由下式近似: θ = arctan ( G y / G x ) \\theta = \\arctan \\left( G_y /G_x \\right) θ=arctan(Gy/Gx)
1.2.2 实现代码
下面代码中,使用 Sobel() 函数计算:
- 分别计算两个方向(x方向,y方向)的Sobel边缘图像;
- 获得两个方向的组合梯度;
下面是OpenCV中的Sobel边缘检测算子函数调用格式:
Sobel(src, ddepth, dx, dy)
参数 ddepth 表示输出图像的精度, dx,dy表示两个方向求导的阶次,比如:
- dx=1,dy=0,表示计算x方向上的一阶导数;
如果 dx=1,dy=1,那么计算图像在两个方面上的一阶导数Sobel图像。
- Python
# Sobel Edge Detection
sobelx = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=5) # Sobel Edge Detection on the X axis
sobely = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=0, dy=1, ksize=5) # Sobel Edge Detection on the Y axis
sobelxy = cv2.Sobel(src=img_blur, ddepth=cv2.CV_64F, dx=1, dyPython+opencv利用sobel进行边缘检测(细节讲解)
Python 图像边缘检测 | 利用 opencv 和 skimage 的 Canny 算法