自定义线性滤波
线性滤波器:将小滑块与图像做卷积,小滑块就是所谓的核,它是一个固定大小的数值数组。在该数组中有一个锚点,一般位于数组中央。
如何将核与图像做卷积?
将核的锚点放在特定的像素上,同时核内其他值与该像素邻域的各像素重合。
将核内各值与对应的图像像素值相乘,然后相加,再将得到的结果放在与锚点对应的像素上。
对图像中的所有像素都进行以上的操作。
下面来看一下,对与三阶的手动实现:
Mat Filter(const Mat src,const Mat kernel)
{
Mat dst,temp,s;
dst = Mat::zeros(src.size(),src.type());
kernel.copyTo(s);
int height = src.rows;
int width = src.cols;
int k_size = kernel.rows;
int add = (k_size - 1)/2;
copyMakeBorder(src,temp,add,add,add,add,BORDER_CONSTANT,Scalar::all(1));
uchar* pre;
uchar* cur;
uchar* next;
int* ker = s.ptr<int>(0);
for(int row = 0;row < height-1;row++)
{
pre = temp.ptr<uchar>(row-1);
cur = temp.ptr<uchar>(row);
next = temp.ptr<uchar>(row+1);
for(int col = 0;col < width - 1;col++)
{
dst.at<uchar>(row,col) = saturate_cast<uchar>(pre[col-1]*int(ker[0])+pre[col]*int(ker[1])+pre[col+1]*int(ker[2])
+cur[col-1]*int(ker[3])+cur[col]*int(ker[4])+cur[col+1]*int(ker[5])
+next[col-1]*int(ker[6])+next[col]*int(ker[7])+next[col+1]*int(ker[8]));
}
}
imshow("dst",dst);
return dst;
}
其中,copyMakeBorder()用来给原图像添加边框。其他的都是常规操作。
有个坑,需要注意的是,当我们的核中存在负数时,我们千万要注意,如何取值。
Tips:在变成的过程中,如何出现不是图像的矩阵,一般使用Mat_来定义,如果是图像,就使用Mat 来定义。
当然了,OpenCV也给我们提供了相关的API:
filter2D(
输入图像,
输出图像,
输出图像的深度,为负值,深度与原图一样,
kernel,
锚点位置,默认Point(-1,-1)
delta,默认为0
BORDER_DEFAULT
);
下面时完整的代码:
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
Mat Filter(const Mat src,const Mat kernel);
int main(int argc,char** argv)
{
Mat src = imread("/home/dynamicw/Project/C++_Project/opencvtest/src/lesson01/source/map.png",0);
imshow("src",src);
Mat kernel = (Mat_<int>(3,3) << 1,-2,1,2,-4,2,1,-2,1);
Filter(src,kernel);
Mat dst;
filter2D(src,dst,-1,kernel,Point(-1,-1),0,BORDER_DEFAULT);
imshow("api",dst);
waitKey(0);
return 0;
}
Mat Filter(const Mat src,const Mat kernel)
{
Mat dst,temp,s;
dst = Mat::zeros(src.size(),src.type());
kernel.copyTo(s);
int height = src.rows;
int width = src.cols;
int k_size = kernel.rows;
int add = (k_size - 1)/2;
copyMakeBorder(src,temp,add,add,add,add,BORDER_CONSTANT,Scalar::all(1));
uchar* pre;
uchar* cur;
uchar* next;
int* ker = s.ptr<int>(0);
for(int row = 0;row < height-1;row++)
{
pre = temp.ptr<uchar>(row-1);
cur = temp.ptr<uchar>(row);
next = temp.ptr<uchar>(row+1);
for(int col = 0;col < width - 1;col++)
{
dst.at<uchar>(row,col) = saturate_cast<uchar>(pre[col-1]*int(ker[0])+pre[col]*int(ker[1])+pre[col+1]*int(ker[2])
+cur[col-1]*int(ker[3])+cur[col]*int(ker[4])+cur[col+1]*int(ker[5])
+next[col-1]*int(ker[6])+next[col]*int(ker[7])+next[col+1]*int(ker[8]));
}
}
imshow("dst",dst);
return dst;
}