自定义线性滤波

自定义线性滤波

线性滤波器:将小滑块与图像做卷积,小滑块就是所谓的核,它是一个固定大小的数值数组。在该数组中有一个锚点,一般位于数组中央。
如何将核与图像做卷积?
将核的锚点放在特定的像素上,同时核内其他值与该像素邻域的各像素重合。
将核内各值与对应的图像像素值相乘,然后相加,再将得到的结果放在与锚点对应的像素上。
对图像中的所有像素都进行以上的操作。

下面来看一下,对与三阶的手动实现:

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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值