濾波、形態學腐蝕與卷積(合集)

https://blog.csdn.net/qq_36285879/article/details/82810705ios

S1.1 濾波、形態學腐蝕與卷積(合集)編程

參考:《學習OpenCV3》、《數字圖像處理編程入門》
文章目錄less

S1.1 濾波、形態學腐蝕與卷積(合集)
濾波器
簡單模糊與方形濾波
中值濾波
高斯濾波
雙邊濾波
導數和梯度
Sobel算子
Scharr濾波器
拉普拉斯變換
圖像形態學
膨脹&腐蝕
通用形態學函數
開操做與閉操做
形態學梯度
頂帽和黑帽
濾波器ide

毛星雲那本有濾波器源碼解析。函數

簡單模糊與方形濾波學習

用blur函數實現
在imgproc中咱們找到定義:(爲了你們訓練英文,就不翻譯了,實際上是我懶-。-)ui

/*
The call `blur(src, dst, ksize, anchor, borderType)` is equivalent to `boxFilter(src, dst, src.type(), anchor, true, borderType)`.和boxFilter相等,待會會講this

@param src input image; it can have any number of channels, which are processed independently, but the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src.
@param ksize blurring kernel size.
@param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel
center.默認爲中心
@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes
@sa boxFilter, bilateralFilter, GaussianBlur, medianBlur
*/
CV_EXPORTS_W void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>spa

using namespace std;
using namespace cv;.net

int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst0, dst1, dst2, dst3;

blur(src, dst0, Size(5,5), Point(-1,-1), BORDER_DEFAULT);

imshow("src", src);
imshow("blur5x5,default", dst0);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
這是一種低通濾波器(low pass filter),把中間像素值替換爲21x21個像素的平均值。

在連接中就講到:

在灰度連續變化的圖象中,若是出現了與相鄰象素的灰度相差很大的點,好比說一片暗區中忽然出現了一個亮點,人眼能很容易覺察到。就象看老電影時,因爲膠片太舊,屏幕上常常會出現一些亮斑。這種狀況被認爲是一種噪聲。灰度突變在頻域中表明瞭一種高頻份量,低通濾波器的做用就是濾掉高頻份量,從而達到減小圖象噪聲的目的。固然這種方法會對本來的圖像形成傷害。

用boxFilter函數實現
多了一個ddepth參數(圖像深度),一個normalize參數(歸不歸一化,就是除不除濾波器面積)

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst0, dst1, dst2, dst3;

blur(src, dst0, Size(11,11), Point(-1,-1), BORDER_DEFAULT);
boxFilter(src, dst1, CV_8U, Size(11, 11), Point(-1, -1), true, BORDER_DEFAULT);
boxFilter(src, dst2, CV_8U, Size(11, 11), Point(-1, -1), false, BORDER_DEFAULT);
boxFilter(src, dst3, CV_16U, Size(11, 11), Point(-1, -1), false, BORDER_DEFAULT);

imshow("src", src);
imshow("blur11x11,default", dst0);
imshow("boxFilter11x11,default", dst1);
imshow("boxFilter11x11,false,default", dst2);
imshow("boxFilter11x11,16U,default", dst3);


waitKey(0);
return 0;
}
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


中值濾波

以前找的是平均值,如今找的是中值。這也是一種低通濾波器

參數類型Size也變爲了int,只能處理正方形區域。(不知道爲啥要這樣改)

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst0, dst1, dst2, dst3;

blur(src, dst0, Size(11,11), Point(-1,-1), BORDER_DEFAULT);
medianBlur(src, dst1, 11);

imshow("src", src);
imshow("blur11x11,default", dst0);
imshow("medianBlur11", dst1);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22


頗有藝術風格呀。可能就是由於中值濾波是實實在在的圖像原有的像素值的緣由。

高斯濾波

是一種有效的濾波器。

由於以模板中心位置爲原點,因此二維高斯公式中的μ1與μ2 \mu_1與\mu2μ
1

與μ2都等於0。

σ \sigmaσ越大,高斯函數越不凸,對應的卷積模板大小也就是越大。

/*
@param src input image; the image can have any number of channels, which are processed
independently, but the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.輸入
@param dst output image of the same size and type as src.輸出
@param ksize Gaussian kernel size. ksize.width and ksize.height can differ but they both must be positive and odd. Or, they can be zero's and then they are computed from sigma.

@param sigmaX Gaussian kernel standard deviation in X direction.
@param sigmaY Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be equal to sigmaX, if both sigmas are zeros, they are computed from ksize. width and ksize.height, respectively (see #getGaussianKernel for details); to fully control the result regardless of possible future modifications of all this semantics, it is recommended to specify all of ksize, sigmaX, and sigmaY.若是sigmaY=0,(默認也是0),就和sigmaX相等。若是sigmaX=sigmaY=0,sigmaX和sigmaY自動適應ksize。具體看getGaussianKernel函數

@param borderType pixel extrapolation method, see #BorderTypes

@sa sepFilter2D, filter2D, blur, boxFilter, bilateralFilter, medianBlur
*/
CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
getGaussianKernel函數
getGaussianKernel返回一個高斯核矩陣,不過它輸出的是一維矩陣。。。具體能夠看這篇blog:

https://blog.csdn.net/u012633319/article/details/80921023

CV_EXPORTS_W Mat getGaussianKernel( int ksize, double sigma, int ktype = CV_64F );
1
高斯濾波演示
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst0, dst1, dst2, dst3;

blur(src, dst0, Size(11,11), Point(-1,-1), BORDER_DEFAULT);
medianBlur(src, dst1, 11);
GaussianBlur(src, dst2, Size(11,11), 0, 0);

imshow("src", src);
imshow("blur11x11,default", dst0);
imshow("medianBlur11", dst1);
imshow("GraussianBlur11,1,1", dst2);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


能夠看出,因爲增強與鄰域的關係,高斯濾波更不模糊。(也有多是參數的緣由)

高斯模糊把邊緣也模糊了,邊緣變粗。

雙邊濾波

能解決高斯不能解決的邊緣問題。

《學習OpenCV》說能產生卡通效果,我感受看不出來,若是調的好,說不定能產生倩女幽魂的效果。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst0, dst1, dst2, dst3;

blur(src, dst0, Size(11,11), Point(-1,-1), BORDER_DEFAULT);
medianBlur(src, dst1, 11);
GaussianBlur(src, dst2, Size(11,11), 2, 0);
bilateralFilter(src, dst3, 16, 150, 150);

imshow("src", src);
imshow("blur11x11,default", dst0);
imshow("medianBlur11", dst1);
imshow("GraussianBlur11,1,1", dst2);
imshow("bilateralFilter11", dst3);

waitKey(0);
return 0;
}
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


導數和梯度

卷積能夠近似計算導數,固然這個涉及時域的知識。

從梯度圖咱們能夠觀察到圖像的邊緣了。

Sobel算子

百度百科就能夠理解Sobel算子是怎麼回事了:

https://baike.baidu.com/item/Sobel算子/11000092?fr=aladdin

其實就是經常使用的兩個固定模板。

固然仍是強烈推薦好書:《數字圖像處理編程入門》:微盤數字圖像處理編程入門 裏面用很簡潔的方法解釋了Sobel爲啥能檢測邊緣。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{

Mat src = imread("images/favorite/Lena.jpg", 0);
Mat dst0, dst1, dst2, dst3, dst4;

Sobel(src, dst0, CV_8U, 1, 1);
Sobel(src, dst1, CV_8U, 0, 1);
Sobel(src, dst2, CV_8U, 1, 0);
Sobel(src, dst3, CV_8U, 1, 2);
Sobel(src, dst4, CV_8U, 2, 1);

 

imshow("src", src);
imshow("Sobel,1,1", dst0);
imshow("Sobel,0,1", dst1);
imshow("Sobel,1,0", dst2);
imshow("Sobel,1,2", dst3);
imshow("Sobel,2,1", dst4);


waitKey(0);
return 0;
}
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


咱們對x求導則獲得豎的邊緣,對y求導獲得橫的邊緣。

Sobel算子的缺點是核較小的時候準確率不高。對於大型的核,精度不太顯著。(用Scharr濾波器能夠解決)【不是很理解】

Scharr濾波器

同Sobel同樣,是經常使用的固定模板。

把Sobel函數的ksize設置爲CV_SCHARR便可。

能夠本身試一下,感受沒差。

拉普拉斯變換

經典變換

這是一種高通濾波器。(中間爲負數)

直接上代碼好了:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src = imread("images/favorite/Lena.jpg");
Mat dst0, dst1, dst2, dst3, dst4;

Laplacian(src, dst0, CV_8U, 1);
Laplacian(src, dst2, CV_8U, 3);

imshow("src", src);
imshow("Laplacian,1", dst0);
imshow("Laplacian,3", dst2);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22


效果的確很好。

圖像形態學

圖像形態學能作出好玩的一些操做。

膨脹&腐蝕

膨脹和腐蝕是相反的一組操做。它依據圖像的亮度。

在OpenCV中,膨脹和腐蝕的邊界用的的空白常量填充(BORDER_CONSTANT)。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src;
Mat dst0, dst1;

src = imread("images/favorite/Lena.jpg");

// int g_nStructElementSize = 3;

// Mat element0 = getStructuringElement(MORPH_RECT,
// Size(2*g_nStructElementSize+1, 2*g_nStructElementSize+1),
// Point(g_nStructElementSize, g_nStructElementSize));
// Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));

erode(src, dst0, Mat());
dilate(src, dst1, Mat());

imshow("erode", dst0);
imshow("dilate", dst1);

waitKey(0);
return 0;
}
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


左邊楊冪,右邊白眼妞。哈哈哈。

另外,膨脹操做能把一張小狗圖變成毛絨小狗圖。

通用形態學函數

這個函數包含了多種形態學方法,由參數op決定:

操做值 形態學操做名 是否須要零時圖像
cv::MOP_OPEN 開操做 否
cv::MOP_CLOSE 閉操做 否
cv::MOP_GRADIENT 形態學梯度 老是須要
cv::MOP_TOPHAT 頂帽操做 就地須要
cv::MOP_BACKHAT 底帽操做 就地須要
開操做與閉操做

開操做就把圖像先腐蝕後膨脹。閉操做反之。

當你設定屢次迭代的時候,實際順序是:膨脹-膨脹-腐蝕-腐蝕

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src;
Mat dst0, dst1, dst2, dst3;

src = imread("images/favorite/Lena.jpg");

morphologyEx(src, dst0, CV_MOP_OPEN, Mat(), Point(-1, -1), 2);
morphologyEx(src, dst1, CV_MOP_OPEN, Mat(), Point(-1, -1), 3);
morphologyEx(src, dst2, CV_MOP_CLOSE, Mat(), Point(-1, -1), 2);
morphologyEx(src, dst3, CV_MOP_CLOSE, Mat(), Point(-1, -1), 3);

imshow("open2", dst0);
imshow("open3", dst1);
imshow("close2", dst2);
imshow("close3", dst3);

waitKey(0);
return 0;
}
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


形態學梯度

gradient(src)=dilate(src)−erode(src) gradient(src) = dilate(src) - erode(src)
gradient(src)=dilate(src)−erode(src)

//
//// cout << src;
// cvtColor(src, src, CV_HSV2BGR);
// imshow("src", src);
//
// waitKey(0);
// return 0;
//}


//16.腐蝕與膨脹
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>

using namespace std;
using namespace cv;

int main()
{
Mat src;
Mat dst0, dst1, dst2, dst3;

src = imread("images/favorite/Lena.jpg", 0);

morphologyEx(src, dst0, CV_MOP_GRADIENT, Mat());

imshow("gradient", dst0);

waitKey(0);
return 0;
}
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


有點像粉筆畫。

頂帽和黑帽

TopHat(src)=src−open(src)BackHat(src)=close(src)−src TopHat(src) = src-open(src)\\BackHat(src)= close(src) - srcTopHat(src)=src−open(src)BackHat(src)=close(src)−src

相關文章
相關標籤/搜索