1.邊緣檢測(cè)原理
圖像的邊緣指的是圖像中像素灰度值突然發(fā)生變化的區(qū)域,如果將圖像中的每一行像素和每一列像素都描述成一個(gè)關(guān)于灰度值的函數(shù),那么圖像的邊緣對(duì)應(yīng)在灰度值函數(shù)中是函數(shù)值突然變大的區(qū)域。函數(shù)值得變化趨勢(shì)可以用導(dǎo)數(shù)描述,當(dāng)函數(shù)值突然變大時(shí),導(dǎo)數(shù)也必然會(huì)變大,而函數(shù)值變化較為平緩時(shí),導(dǎo)數(shù)值也比較小,因此可以通過(guò)尋找導(dǎo)數(shù)值較大的區(qū)域?qū)ふ液瘮?shù)中突然變化的區(qū)域,進(jìn)而確定圖像中的邊緣位置。
由于圖像是練得信號(hào),因此我們可以用臨近的兩個(gè)像素值來(lái)表示像素灰度值函數(shù)的導(dǎo)數(shù),求導(dǎo)形式表示如下:
d
f
(
x
,
y
)
d
x
=
f
(
x
,
y
)
?
f
(
x
?
1
,
y
)
\frac{df(x,y)}{dx} = f(x,y) - f(x-1,y)
dxdf(x,y)?=f(x,y)?f(x?1,y)
這種對(duì)x軸方向的濾波器為
[
?
1
1
]
\begin{bmatrix} -1 & 1 \end{bmatrix}
[?1?1?],同樣對(duì)y軸方向的求導(dǎo)對(duì)應(yīng)的濾波器為
[
?
1
1
]
T
\begin{bmatrix} -1 & 1 \end{bmatrix}^T
[?1?1?]T 。
而表示某個(gè)像素處的梯度,最接近的方式是求取前一個(gè)像素和后一個(gè)像素的差值,于是修改上式為:
d
f
(
x
,
y
)
d
x
=
f
(
x
+
1
,
y
)
?
f
(
x
?
1
,
y
)
2
\frac{df(x,y)}{dx} = \frac{f(x+1,y) - f(x-1,y)}{2}
dxdf(x,y)?=2f(x+1,y)?f(x?1,y)?
改進(jìn)的求導(dǎo)方式對(duì)應(yīng)的濾波器在 X 方向和 Y 方向分別為
[
?
0.5
0
0.5
]
\begin{bmatrix} -0.5 & 0 & 0.5 \end{bmatrix}
[?0.5?0?0.5?] 和
[
?
0.5
0
0.5
]
T
\begin{bmatrix} -0.5 & 0 & 0.5 \end{bmatrix}^T
[?0.5?0?0.5?]T 。
根據(jù)這種方式,也可以使用下面的濾波器計(jì)算 4 5 ° 45^\circ 45° 方向的梯度:
X Y = [ 1 0 0 ? 1 ] Y X = [ 0 1 ? 1 0 ] XY = \begin{bmatrix} 1 & 0 \\ 0 & -1 \\ \end{bmatrix} YX = \begin{bmatrix} 0 & 1 \\ -1 & 0 \\ \end{bmatrix} XY=[10?0?1?]YX=[0?1?10?]
圖像的邊緣有可能是由高像素值變?yōu)榈拖袼刂?,也有可能是由低像素值變成高像素值。通過(guò)上面的梯度公式,得到正數(shù)值表示像素值突然由低變高,得到的負(fù)數(shù)值表示像素值由高到低,這兩種都是圖像的邊緣,因此,為了在圖像中同時(shí)表示出這兩種邊緣信息,需要將計(jì)算的結(jié)果求取絕對(duì)值。
OpenCV中提供了 convertScaleAbs()
函數(shù)用于計(jì)算矩陣中的所有數(shù)據(jù)的的絕對(duì)值:
void convertScaleAbs(
InputArray src, // 輸入圖像
OutputArray dst, // 輸出圖像
double alpha = 1, // 縮放因子
double beta = 0 // 偏置值
);
下面代碼中給出了利用 filter2D()
函數(shù)實(shí)現(xiàn)圖像邊緣檢測(cè)的算法,需要說(shuō)明的是,由于求取邊緣的結(jié)果可能會(huì)有負(fù)值,不在原始圖像的 CV_8U 數(shù)據(jù)范圍內(nèi),因此濾波后的圖像數(shù)據(jù)類型不要用 “-1” ,而應(yīng)該為 CV_16S。
#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log
using namespace cv;
using namespace std;
int main()
{
cout << "OpenCV Version: " << CV_VERSION << endl;
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//創(chuàng)建邊緣檢測(cè)濾波器
Mat kernel1 = (Mat_<float>(1, 2) << 1, -1); //X方向邊緣檢測(cè)濾波器
Mat kernel2 = (Mat_<float>(1, 3) << 1, 0, -1); //X方向邊緣檢測(cè)濾波器
Mat kernel3 = (Mat_<float>(3, 1) << 1, 0, -1); //X方向邊緣檢測(cè)濾波器
Mat kernelXY = (Mat_<float>(2, 2) << 1, 0, 0, -1); //由左上到右下方向邊緣檢測(cè)濾波器
Mat kernelYX = (Mat_<float>(2, 2) << 0, -1, 1, 0); //由右上到左下方向邊緣檢測(cè)濾波器
//讀取圖像,黑白圖像邊緣檢測(cè)結(jié)果較為明顯
Mat img = imread("equalLena.png", IMREAD_ANYCOLOR);
if (img.empty())
{
cout << "請(qǐng)確認(rèn)圖像文件名稱是否正確" << endl;
return -1;
}
Mat result1, result2, result3, result4, result5, result6;
//檢測(cè)圖像邊緣
//以[1 -1]檢測(cè)水平方向邊緣
filter2D(img, result1, CV_16S, kernel1);
convertScaleAbs(result1, result1);
//以[1 0 -1]檢測(cè)水平方向邊緣
filter2D(img, result2, CV_16S, kernel2);
convertScaleAbs(result2, result2);
//以[1 0 -1]'檢測(cè)由垂直方向邊緣
filter2D(img, result3, CV_16S, kernel3);
convertScaleAbs(result3, result3);
//整幅圖像的邊緣
result6 = result2 + result3;
//檢測(cè)由左上到右下方向邊緣
filter2D(img, result4, CV_16S, kernelXY);
convertScaleAbs(result4, result4);
//檢測(cè)由右上到左下方向邊緣
filter2D(img, result5, CV_16S, kernelYX);
convertScaleAbs(result5, result5);
//顯示邊緣檢測(cè)結(jié)果
imshow("result1", result1);
imshow("result2", result2);
imshow("result3", result3);
imshow("result4", result4);
imshow("result5", result5);
imshow("result6", result6);
waitKey(0);
return 0;
}
2.Sobel算子
使用Sobel邊緣檢測(cè)算子提取圖像邊緣的過(guò)程:
1.提取 X 方向的邊緣,X方向的一階 Sobel 邊緣檢測(cè)算子:
[
?
1
0
1
?
2
0
2
?
1
0
1
]
\begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \\ \end{bmatrix}
??1?2?1?000?121?
?
2.提取 Y 方向的邊緣,Y方向的一階 Sobel 邊緣檢測(cè)算子:
[
?
1
?
2
?
1
0
0
0
1
2
1
]
\begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \\ \end{bmatrix}
??101??202??101?
?
3.綜合兩個(gè)方向的邊緣信息得到整幅圖像的邊緣。由兩個(gè)方向的邊緣得到整幅圖像的邊緣有兩種計(jì)算方式,第一種是求取兩幅圖像對(duì)應(yīng)像素的像素值的絕對(duì)值之和,第二種是求取兩幅圖像對(duì)應(yīng)像素值的平方和的二次方根:
I
(
x
,
y
)
=
I
x
(
x
,
y
)
2
+
I
y
(
x
,
y
)
2
I
(
x
,
y
)
=
∣
I
x
(
x
,
y
)
∣
+
∣
I
y
(
x
,
y
)
∣
\begin{align} I(x,y) &= \sqrt{I_x(x,y)^2 + I_y(x,y)^2} \\ I(x,y) &= |I_x(x,y)| + |I_y(x,y)| \\ \end{align}
I(x,y)I(x,y)?=Ix?(x,y)2+Iy?(x,y)2?=∣Ix?(x,y)∣+∣Iy?(x,y)∣??
OpenCV提供了對(duì)圖像提取 Sobel 邊緣的 Sobel()
函數(shù):
void Sobel(
InputArray src,
OutputArray dst,
int ddepth, // 輸出圖像的數(shù)據(jù)類型,-1表示自動(dòng)選擇
int dx, // X方向差分階數(shù),即使用幾階Sobel算子
int dy, // Y方向差分階數(shù),即使用幾階Sobel算子
int ksize = 3, // Sobel算子尺寸,必須是1,3,5,7
double scale = 1, // 對(duì)導(dǎo)數(shù)計(jì)算結(jié)果進(jìn)行縮放
double delta = 0, // 偏置值
int borderType = BORDER_DEFAULT
);
dx、dy、ksize:任意一個(gè)方向的差分階數(shù)都需要小于算子的尺寸。但有以下特殊情況:當(dāng)ksize=1時(shí),任意一個(gè)方向的階數(shù)都需要小于3。
一般情況下,當(dāng)差分階數(shù)的最大值取1時(shí),ksize取3;當(dāng)差分階數(shù)的最大值取2時(shí),ksize取5;當(dāng)差分階數(shù)的最大值取3時(shí),ksize取7;
當(dāng)ksize=1時(shí),程序中使用的算子尺寸不再是正方形,而是3x1或者1x3。
#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log
using namespace cv;
using namespace std;
int main()
{
cout << "OpenCV Version: " << CV_VERSION << endl;
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//讀取圖像,黑白圖像邊緣檢測(cè)結(jié)果較為明顯
Mat img = imread("equalLena.png", IMREAD_ANYCOLOR);
if (img.empty())
{
cout << "請(qǐng)確認(rèn)圖像文件名稱是否正確" << endl;
return -1;
}
Mat resultX, resultY, resultXY;
//X方向一階邊緣
Sobel(img, resultX, CV_16S, 1, 0, 1);
convertScaleAbs(resultX, resultX);
//Y方向一階邊緣
Sobel(img, resultY, CV_16S, 0, 1, 3);
convertScaleAbs(resultY, resultY);
//整幅圖像的一階邊緣
resultXY = resultX + resultY;
//顯示圖像
imshow("resultX", resultX);
imshow("resultY", resultY);
imshow("resultXY", resultXY);
waitKey(0);
return 0;
}
3.Scharr算子
雖然Sobel算子可以有效地提取圖像邊緣,但是對(duì)于圖像中較弱的邊緣提取效果較差。因此,為了能夠有效地提出較弱的邊緣,需要將像素值間的差距值增大。
Socharr算子是對(duì)Sobel算子差異性的增強(qiáng),兩者在檢測(cè)圖像邊緣的原理和使用方式上相同,Scharr算子在X方向和Y方向的邊緣檢測(cè)算子:
G
x
=
[
?
3
0
3
?
10
0
10
?
3
0
3
]
G
y
=
[
?
3
?
10
?
3
0
0
0
3
10
3
]
G_x = \begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3 \\ \end{bmatrix} G_y = \begin{bmatrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ 3 & 10 & 3 \\ \end{bmatrix}
Gx?=
??3?10?3?000?3103?
?Gy?=
??303??10010??303?
?
OpenCV提供了對(duì)圖像提取Scharr邊緣的 Scharr()
函數(shù):
void Scharr(
InputArray src,
OutputArray dst,
int ddepth,
int dx,
int dy,
double scale = 1,
double delta = 0,
int borderType = BORDER_DEFAULT
);
dx和dy只能有一個(gè)為1,并且不能同時(shí)為0。
下面代碼中,分別提取X方向和Y方向邊緣,并利用這兩個(gè)方向的邊緣求取整幅圖像的邊緣。可以看出Scharr算子比Sobel算子提取到更微弱的邊緣。
#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log
using namespace cv;
using namespace std;
int main()
{
cout << "OpenCV Version: " << CV_VERSION << endl;
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//讀取圖像,黑白圖像邊緣檢測(cè)結(jié)果較為明顯
Mat img = imread("equalLena.png", IMREAD_ANYDEPTH);
if (img.empty())
{
cout << "請(qǐng)確認(rèn)圖像文件名稱是否正確" << endl;
return -1;
}
Mat resultX, resultY, resultXY;
//X方向一階邊緣
Scharr(img, resultX, CV_16S, 1, 0);
convertScaleAbs(resultX, resultX);
//Y方向一階邊緣
Scharr(img, resultY, CV_16S, 0, 1);
convertScaleAbs(resultY, resultY);
//整幅圖像的一階邊緣
resultXY = resultX + resultY;
//顯示圖像
imshow("resultX", resultX);
imshow("resultY", resultY);
imshow("resultXY", resultXY);
waitKey(0);
return 0;
}
4.生成邊緣檢測(cè)濾波器
Scharr算子只有上面的兩種,而Sobel算子有不同的尺寸、不同階數(shù)。OpenCV中提供了 getDerivKernels()
函數(shù)可以得到不同尺寸、不同階數(shù)的Sobel算子和Scharr算子濾波器。
void getDerivKernels(
OutputArray kx, // 行濾波器系數(shù)輸出矩陣 ksize x 1
OutputArray ky, // 列濾波器系數(shù)輸出矩陣 ksize x 1
int dx, // X方向?qū)?shù)的階次
int dy, // Y方向?qū)?shù)的階次
int ksize, // 濾波器的大小可以為FILTER_SCHARR、1、3、5、7
bool normalize = false, // 是否歸一化
int ktype = CV_32F // 濾波器系數(shù)類型,CV_32F、CV_64F
);
下面的例子中給出利用 getDerivKernels()
函數(shù)生成Sobel算子和Scharr算子的代碼:
#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log
using namespace cv;
using namespace std;
int main()
{
cout << "OpenCV Version: " << CV_VERSION << endl;
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
Mat sobel_x1, sobel_y1, sobel_x2, sobel_y2, sobel_x3, sobel_y3; //存放分離的Sobel算子
Mat scharr_x, scharr_y; //存放分離的Scharr算子
Mat sobelX1, sobelX2, sobelX3, scharrX; //存放最終算子
//一階X方向Sobel算子
getDerivKernels(sobel_x1, sobel_y1, 1, 0, 3);
sobel_x1 = sobel_x1.reshape(CV_8U, 1);
sobelX1 = sobel_y1 * sobel_x1; //計(jì)算濾波器
//二階X方向Sobel算子
getDerivKernels(sobel_x2, sobel_y2, 2, 0, 5);
sobel_x2 = sobel_x2.reshape(CV_8U, 1);
sobelX2 = sobel_y2 * sobel_x2; //計(jì)算濾波器
//三階X方向Sobel算子
getDerivKernels(sobel_x3, sobel_y3, 3, 0, 7);
sobel_x3 = sobel_x3.reshape(CV_8U, 1);
sobelX3 = sobel_y3 * sobel_x3; //計(jì)算濾波器
//X方向Scharr算子
getDerivKernels(scharr_x, scharr_y, 1, 0, FILTER_SCHARR);
scharr_x = scharr_x.reshape(CV_8U, 1);
scharrX = scharr_y * scharr_x; //計(jì)算濾波器
//輸出結(jié)果
cout << "X方向一階Sobel算子:" << endl << sobelX1 << endl;
cout << "X方向二階Sobel算子:" << endl << sobelX2 << endl;
cout << "X方向三階Sobel算子:" << endl << sobelX3 << endl;
cout << "X方向Scharr算子:" << endl << scharrX << endl;
waitKey(0);
return 0;
}
/*
X方向一階Sobel算子:
[-1, 0, 1;
-2, 0, 2;
-1, 0, 1]
X方向二階Sobel算子:
[1, 0, -2, 0, 1;
4, 0, -8, 0, 4;
6, 0, -12, 0, 6;
4, 0, -8, 0, 4;
1, 0, -2, 0, 1]
X方向三階Sobel算子:
[-1, 0, 3, 0, -3, 0, 1;
-6, 0, 18, 0, -18, 0, 6;
-15, 0, 45, 0, -45, 0, 15;
-20, 0, 60, 0, -60, 0, 20;
-15, 0, 45, 0, -45, 0, 15;
-6, 0, 18, 0, -18, 0, 6;
-1, 0, 3, 0, -3, 0, 1]
X方向Scharr算子:
[-3, 0, 3;
-10, 0, 10;
-3, 0, 3]
*/
5.Laplacian算子
上述的邊緣檢測(cè)算子都具有方向性,因此都需要分別求取X方向的邊緣和Y方向的邊緣,之后將兩個(gè)方向的邊緣綜合得到圖像的整體邊緣。Laplacian算子具有各個(gè)方向同性的特點(diǎn),能夠?qū)θ我夥较虻倪吘夁M(jìn)行提取,具有無(wú)方向性的優(yōu)點(diǎn)。
Laplacian算子是一種二階導(dǎo)數(shù)算子,對(duì)噪聲比較敏感,因此常需要配合高斯濾波一起使用。
二維圖像函數(shù)
f
(
x
,
y
)
f(x,y)
f(x,y) ,圖像的Laplace運(yùn)算二階導(dǎo)數(shù)定義:
?
2
f
(
x
,
y
)
=
?
2
f
?
x
2
+
?
2
f
?
y
2
\nabla^2 f(x,y) = \frac{\partial^2 f}{\partial x^2} + \frac{\partial^2 f}{\partial y^2}
?2f(x,y)=?x2?2f?+?y2?2f?
對(duì)于二維離散圖像而言,圖像的Laplace可表示吐下:
?
2
f
(
x
,
y
)
=
f
(
x
+
1
,
y
)
+
f
(
x
?
1
,
y
)
+
f
(
x
,
y
+
1
)
+
f
(
x
,
y
?
1
)
?
4
f
(
x
,
y
)
\nabla^2 f(x,y) = f(x+1,y) + f(x-1,y) + f(x,y+1) + f(x,y-1) - 4f(x,y)
?2f(x,y)=f(x+1,y)+f(x?1,y)+f(x,y+1)+f(x,y?1)?4f(x,y)
根據(jù)離散Laplace表達(dá)式,可以得到其濾波器:
G
1
=
[
0
1
0
1
?
4
1
0
1
0
]
G
2
=
[
1
1
1
1
?
8
1
1
1
1
]
G_1 = \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \\ \end{bmatrix} G_2 = \begin{bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \\ \end{bmatrix}
G1?=
?010?1?41?010?
?G2?=
?111?1?81?111?
?
G
1
G_1
G1? 與
G
2
G_2
G2? 分別為離散拉普拉斯算子的模版與拓展模版,利用函數(shù)模版可以將圖像中的奇異點(diǎn)如亮點(diǎn)變得更亮。對(duì)于圖像中灰度變化劇烈的區(qū)域,拉普拉斯算子能實(shí)現(xiàn)其邊緣檢測(cè)。
OpenCV提供了Laplacian算子提取圖像邊緣的 Laplacian()
函數(shù):
void Laplacian(
InputArray src,
OutputArray dst,
int ddepth,
int ksize = 1, // 濾波器大小,必須為正奇數(shù)
double scale = 1,
double delta = 0,
int borderType = BORDER_DEFAULT
);
ksize=1時(shí),采用 G 1 G_1 G1? 拉普拉斯算子。
下面代碼中,采用圖像去噪后通過(guò)拉普拉斯算子提取邊緣變得更加準(zhǔn)確:
#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log
using namespace cv;
using namespace std;
int main()
{
cout << "OpenCV Version: " << CV_VERSION << endl;
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//讀取圖像,黑白圖像邊緣檢測(cè)結(jié)果較為明顯
Mat img = imread("equalLena.png", IMREAD_ANYDEPTH);
if (img.empty())
{
cout << "請(qǐng)確認(rèn)圖像文件名稱是否正確" << endl;
return -1;
}
Mat result, result_g, result_G;
//未濾波提取邊緣
Laplacian(img, result, CV_16S, 3, 1, 0);
convertScaleAbs(result, result);
//濾波后提取Laplacian邊緣
GaussianBlur(img, result_g, Size(3, 3), 5, 0); //高斯濾波
Laplacian(result_g, result_G, CV_16S, 3, 1, 0);
convertScaleAbs(result_G, result_G);
//顯示圖像
imshow("result", result);
imshow("result_G", result_G);
waitKey(0);
return 0;
}
6.Canny算法
Canny算法不容易受到噪聲的影響,能夠識(shí)別圖像中的若邊緣和強(qiáng)邊緣,并結(jié)合強(qiáng)弱邊緣的位置關(guān)系,綜合給出圖像整體的邊緣信息。Canny邊緣檢測(cè)算法是目前最優(yōu)越的邊緣檢測(cè)算法之一。該方法的檢測(cè)過(guò)程:
1.使用高斯濾波去噪,平滑圖像,下面是5x5的高斯濾波器:
G
=
1
139
[
2
4
5
4
2
4
9
12
9
4
5
12
15
12
5
4
9
12
9
4
2
4
5
4
2
]
G = \frac{1}{139} \begin{bmatrix} 2 & 4 & 5 & 4 & 2 \\ 4 & 9 & 12 & 9 & 4 \\ 5 & 12 & 15 & 12 & 5 \\ 4 & 9 & 12 & 9 & 4 \\ 2 & 4 & 5 & 4 & 2 \\ \end{bmatrix}
G=1391?
?24542?491294?51215125?491294?24542?
?
2.計(jì)算圖像中每個(gè)像素的梯度幅值與方向。可以通過(guò)Sobel算子分別檢測(cè)圖像X方向和Y方向邊緣,之后利用下面公式計(jì)算梯度的方向和幅值:
θ
=
a
r
c
t
a
n
(
I
y
I
x
)
G
=
a
r
c
t
a
n
I
x
2
+
I
y
2
\theta = arctan(\frac{I_y}{I_x}) \\ G = arctan\sqrt{I_x^2 + I_y^2}
θ=arctan(Ix?Iy??)G=arctanIx2?+Iy2??
其中梯度方向近似到下面4個(gè)取值:
0
°
0^\circ
0°、
4
5
°
45^\circ
45°、
9
0
°
90^\circ
90°、
13
5
°
135^\circ
135°
3.利用非極大值抑制算法消除邊緣檢測(cè)帶來(lái)的雜散響應(yīng)。通俗意義上是指尋找像素點(diǎn)局部最大值,將非極大值點(diǎn)所對(duì)應(yīng)的灰度值設(shè)置為背景像素點(diǎn),如像素領(lǐng)域區(qū)域滿足梯度值的局部最優(yōu)值判斷為該像素的邊緣,對(duì)其余非極大值的相關(guān)信息進(jìn)行抑制。
4.應(yīng)用雙閾值法劃分強(qiáng)邊緣和弱邊緣。如果某一像素位置的幅值超過(guò)高閾值,該像素被保留為邊緣;如果某一像素位置的幅值小于低閾值,該像素被排除;如果某一像素位置的幅值在兩個(gè)閾值之間,該像素僅僅在連接到一個(gè)高于閾值的像素時(shí)被保留。推薦高與低閾值比在 2:1
到 3:1
之間。
Canny算法流程復(fù)雜,好在OpenCV中提供了 Canny()
函數(shù)實(shí)現(xiàn)Canny算法檢測(cè)圖像中的邊緣:
void Canny(
InputArray image, // CV_8U
OutputArray edges,
double threshold1, // 第一個(gè)滯后閾值
double threshold2, // 第二個(gè)滯后閾值
int apertureSize = 3, // Sobel算子直徑
bool L2gradient = false // 計(jì)算圖像梯度幅值的方法是否使用L2范數(shù)
);
下面的代碼中,通過(guò)設(shè)置不同的閾值來(lái)比較閾值的大小對(duì)圖像邊緣檢測(cè)效果的影響,可以發(fā)現(xiàn),較高的閾值會(huì)降低噪聲信息的影響,但是也會(huì)減少邊緣信息。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-721885.html
#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log
using namespace cv;
using namespace std;
int main()
{
cout << "OpenCV Version: " << CV_VERSION << endl;
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//讀取圖像,黑白圖像邊緣檢測(cè)結(jié)果較為明顯
Mat img = imread("equalLena.png", IMREAD_ANYDEPTH);
if (img.empty())
{
cout << "請(qǐng)確認(rèn)圖像文件名稱是否正確" << endl;
return -1;
}
Mat resultHigh, resultLow, resultG;
//大閾值檢測(cè)圖像邊緣
Canny(img, resultHigh, 100, 200, 3);
//小閾值檢測(cè)圖像邊緣
Canny(img, resultLow, 20, 40, 3);
//高斯模糊后檢測(cè)圖像邊緣
GaussianBlur(img, resultG, Size(3, 3), 5);
Canny(resultG, resultG, 100, 200, 3);
//顯示圖像
imshow("resultHigh", resultHigh);
imshow("resultLow", resultLow);
imshow("resultG", resultG);
waitKey(0);
return 0;
}
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-721885.html
到了這里,關(guān)于OpenCV15-圖像邊緣檢測(cè):Sobel、Scharr、Laplace、Canny的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!