通过函数滤波
通过API进行滤波处理,滤波算法基本固定,灵活性不大,得到的图片效果只能在一定范围内进行动态调整。例如高斯模糊、均值模糊等利用的滤波算法
自定义滤波算法
图像处理中最基本的就是卷积处理,利用算子在图片不停的移动计算产生我们想要的目的图像。自定义滤波算法的首要做法就是定义算子(卷积核)
常见的算子:
Robert算子:
[
1
0
0
−
1
]
\left [ \begin{matrix} 1 & 0 \\ 0 & -1 \end{matrix} \right]
[100−1]
该算子左上角像素点减去右下角像素点,算子和为0,得出图片较暗,突出斜方向图片细节。
[
0
1
−
1
0
]
\left [ \begin{matrix} 0 & 1 \\ -1 & 0 \end{matrix} \right]
[0−110]
该算子右上角像素点减去左下角像素点,算子和为0,得出图片较暗,突出斜方向图片细节。
Sobel算子:
G
x
=
[
−
1
0
1
−
2
0
2
−
1
0
1
]
Gx= \left [ \begin{matrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{matrix} \right]
Gx=⎣⎡−1−2−1000121⎦⎤
该算子左边像素点减去右边像素点,算子和为0,得出图片较暗,突出水平方向图片细节,本行所在算子乘以2倍,边缘信息更强。
G
y
=
[
−
1
−
2
−
1
0
0
0
1
2
1
]
Gy= \left [ \begin{matrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{matrix} \right]
Gy=⎣⎡−101−202−101⎦⎤
该算子下边像素点减去上边像素点,算子和为0,得出图片较暗,突出垂直方向图片细节,本列所在算子乘以2倍,边缘信息更强。
拉普拉斯算子:
[
0
−
1
0
−
1
4
−
1
0
−
1
0
]
\left [ \begin{matrix} 0 & -1 & 0 \\ -1 & 4 & -1 \\ 0 & -1 & 0 \end{matrix} \right]
⎣⎡0−10−14−10−10⎦⎤
该算子中央像素点的四倍值减去周围像素点,算子和为0,得出图片较暗,突出边缘信息,亮度大的更大,亮度小的更小。
代码
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#define Pic_Path "/home/image/Pictures/"
#define Pic_Name "model.jpg"
using namespace std;
using namespace cv;
int main(int argc, char **argv)
{
string pic = string(Pic_Path) + string(Pic_Name);
cout << pic << endl;
Mat src;
src = imread(pic.c_str());
cv::namedWindow("原始图片",cv::WINDOW_AUTOSIZE);
cv::imshow("原始图片",src);
#if 0
//正向 robert
Mat dst_x;
Mat kernel_x = (cv::Mat_<int>(2,2)<<1,0,0,-1);
cv::filter2D(src,dst_x,src.depth(),kernel_x,cv::Point(-1,-1),0,0);
cv::namedWindow("正斜罗伯特",cv::WINDOW_AUTOSIZE);
cv::imshow("正斜罗伯特",dst_x);
//逆向 robert
Mat dst_y;
Mat kernel_y = (cv::Mat_<int>(2,2)<<0,1,-1,0);
cv::filter2D(src,dst_y,src.depth(),kernel_y,cv::Point(-1,-1),0,0);
cv::namedWindow("反斜罗伯特",cv::WINDOW_AUTOSIZE);
cv::imshow("反斜罗伯特",dst_y);
Mat dst_level;
Mat kernel_level = (cv::Mat_<int>(3,3)<<-1,0,1,-2,0,2,-1,0,1);
cv::filter2D(src,dst_level,src.depth(),kernel_level,cv::Point(-1,-1),0,0);
cv::namedWindow("水平索贝尔",cv::WINDOW_AUTOSIZE);
cv::imshow("水平索贝尔",dst_level);
Mat dst_ver;
Mat kernel_ver = (cv::Mat_<int>(3,3)<<-1,-2,-1,0,0,0,1,2,1);
cv::filter2D(src,dst_ver,src.depth(),kernel_ver,cv::Point(-1,-1),0,0);
cv::namedWindow("垂直索贝尔",cv::WINDOW_AUTOSIZE);
cv::imshow("垂直索贝尔",dst_ver);
Mat dst_lapulas;
Mat kernel_lapulas = (cv::Mat_<int>(3,3)<<0,-1,0,-1,4,-1,0,-1,0);
cv::filter2D(src,dst_lapulas,src.depth(),kernel_lapulas,cv::Point(-1,-1),0,0);
cv::namedWindow("拉普拉斯",cv::WINDOW_AUTOSIZE);
cv::imshow("拉普拉斯",dst_lapulas);
#endif
Mat dst;
int c = 0;
int index = 0;
int ksize = 0;
while(true)
{
c=waitKey(500); //500毫秒
if(c==27) //判断键值是否为esc
break;
ksize = 4+(index%5)*2+1; //定义模糊卷积核尺寸
//生成卷积核 1填充 并除以面积 进行归一化处理 实质是均值滤波 size不断变化而已
Mat mykernel = Mat::ones(Size(ksize, ksize), CV_32F) / (float)(ksize * ksize);
//填充
filter2D(src, dst, -1, mykernel, Point(-1, -1));
index++;
imshow("自定义算子",dst);
}
waitKey(0);
cv::destroyAllWindows();
return 0;
}