数字图像处理之图像滤波与形态学

前言

又咕了一个学期,上学期的东西都没写完,惭愧惭愧。

实验要求

  1. 空域滤波
    1.1 设计高斯滤波器模板函数
    1.2 填充图像,将模板函数与图像进行卷积
    1.3 截取图像,获得滤波后的图像
  2. 腐蚀/膨胀算法
    2.1 读取图片
    2.2 腐蚀/膨胀算法
    2.3 将经过腐蚀或膨胀后的图片显示

代码实现

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <stdlib.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#define LINEAR_X 0
#define SIZE 5
#define PI 3.1415926
using namespace cv;
void threshold(Mat input,Mat &output,int var)
{
int rows = output.rows;
int cols = output.cols;
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
int p=input.at<uchar>(i,j);
if(p>var)
output.at<uchar>(i,j)=255;
else output.at<uchar>(i,j)=0;
}
}
}
//////////////////////滤波//////////////////
// 空域高斯滤波器函数
void Gaussian(Mat input, Mat &output, double sigma){
double weight;//权重
double sum = 0;
double Gaussian_Temp[SIZE][SIZE] = {0};//模板
weight = (2*PI*sigma*sigma);
for(int i =0;i <SIZE;i++)
{
for(int j = 0;j < SIZE;j++)
{
int x = i - SIZE/2;
int y = j - SIZE/2;
Gaussian_Temp[i][j] =exp(-(x*x+y*y)/(2.0*sigma*sigma))/weight;
sum += Gaussian_Temp[i][j];
}
}

for(int i = 0; i < SIZE;i++)
{
for(int j = 0;j < SIZE;j++)
{
Gaussian_Temp[i][j] = Gaussian_Temp[i][j]/sum;//归一化处理
}
}
//卷积
int rows = output.rows;
int cols = output.cols;
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
for(int k=0;k<SIZE;k++)
for(int t=0;t<SIZE;t++)
{
int x=i+k-SIZE/2;
int y=j+t-SIZE/2;
if(x<0||y<0||x>=rows||y>=cols)continue;
int p=input.at<uchar>(x,y);
output.at<uchar>(i,j)+=p*Gaussian_Temp[k][t];
}
if(output.at<uchar>(i,j)>255)output.at<uchar>(i,j)=255;
if(output.at<uchar>(i,j)<0)output.at<uchar>(i,j)=0;
}
}

}
// 膨胀函数
void Dilate(Mat Src, Mat Tem, Mat Dst){
int rows = Dst.rows;
int cols = Dst.cols;
int t_rows = Tem.rows;
int t_cols = Tem.cols;
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
int p = Src.at<uchar>(i,j);
if(p == 0)continue;
for(int k=0;k<t_rows;k++)
for(int t=0;t<t_cols;t++)
{
int x=i+k;
int y=j+t;
if(x<0||y<0||x>=rows||y>=cols)continue;
if(Tem.at<uchar>(k,t) == 1)
Dst.at<uchar>(x,y)=255;
}
}
}
}
// 腐蚀函数
void Erode(Mat Src, Mat Tem, Mat Dst){
int rows = Dst.rows;
int cols = Dst.cols;
int t_rows = Tem.rows;
int t_cols = Tem.cols;
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
int sum = 0;
for(int k=0;k<t_rows;k++)
for(int t=0;t<t_cols;t++)
{
int x=i+k-t_rows/2;
int y=j+t-t_cols/2;
if(x<0||y<0||x>=rows||y>=cols)continue;
sum +=Tem.at<uchar>(k,t)*Src.at<uchar>(x,y);
}
if(sum == 13*255)Dst.at<uchar>(i,j)=255;
}
}
}
int main(int argc,char **argv){
//读取原始图像
Mat src=imread(argv[1],IMREAD_UNCHANGED);
//检查是否读取图像
if(src.empty()){
std::cout<<"Error! Input image cannot be read...\n";
return -1;
}

imshow("src",src);
cvtColor(src,src,COLOR_BGR2GRAY);

Mat dst1=Mat::zeros(src.size(),CV_8UC1);
Mat dst2=Mat::zeros(src.size(),CV_8UC1);
Mat dst3=Mat::zeros(src.size(),CV_8UC1);
Mat Thimg=Mat::zeros(src.size(),CV_8UC1);
threshold(src,Thimg,255/2);

Mat dstOut;
//GaussianBlur(img_out,dstOut,Size(3,3),1,1);
// 空域滤波函数
Gaussian(src,dst1,0.8);

// 膨胀函数
uchar matrix1[5][5] = {{1,1,1,1,1},{1,1,1,1,0}, {1,1,1,0,0}, {1,1,0,0,0}, {1,0,0,0,0}};
Mat Tem1(Size(5,5), CV_8UC1, matrix1);//注意:opencv里的行列顺序是和maltab相反的
//由于Mat矩阵默认的是uchar类型,所以前后一致,定义矩阵时也要定义uchar类型
Dilate(Thimg,Tem1,dst2);

// 腐蚀函数
uchar matrix2[5][5] = {{0,0,1,0,0}, {0,1,1,1,0},{1,1,1,1,1},{0,1,1,1,0},{0,0,1,0,0}};
Mat Tem2(Size(5,5), CV_8UC1, matrix2);//注意:opencv里的行列顺序是和maltab相反的
//由于Mat矩阵默认的是uchar类型,所以前后一致,定义矩阵时也要定义uchar类型
Erode(Thimg,Tem2,dst3);
imshow("高斯滤波",dst1);
imshow("膨胀",dst2);
imshow("腐蚀",dst3);
std::cout << "Press any key to exit...\n";
waitKey(); // Wait for key press
return 0;
}

运行结果

原图
原图
原图
原图