Opencv中图像滤波

看了园子里的博友们,感觉自己也应该把自己以前学习到的东西写下来,通过写下来也正好是一个回顾的过程。于是决定把今年学到了什么写下来,至于还有很多不是很清楚的地方也写下来,以便以后更好的理解。

这个写的是图像滤波。为什么要图像滤波呢,对于我们获取原始图像的时候,难免不被污染,就会有噪声的干扰,于是就有了图像滤波的操作,也就是对目标图像的噪声的抑制。这个操作也就是其他更深一层次的图像分析,图像理解来说的基础。

对于滤波的方法,分频率滤波和空域滤波,这篇主要说的是空域滤波,均值滤波,中值滤波,高斯滤波,跟双边滤波。

具体测试代码参考:

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html#smoothing

我们主要简单分析一下源码。

1、均值滤波。

K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix}
    1 & 1 & 1 & ... & 1 \\
    1 & 1 & 1 & ... & 1 \\
    . & . & . & ... & 1 \\
    . & . & . & ... & 1 \\
    1 & 1 & 1 & ... & 1
   \end{bmatrix}

均值滤波的opencv中的源码在smooth.cpp中为

void cv::blur( InputArray src, OutputArray dst,Size ksize, Point anchor, int borderType )
{
    boxFilter( src, dst, -1, ksize, anchor, true, borderType );
} 调用了盒子滤波,Point anchor=Point(-1,-1),int borderType=BORDER_DEFAULT默认值

对于盒子滤波在SURF算法中提到,对于盒子滤波本人的理解就是,对于均值滤波每个像素点以1加权,而盒子滤波不一定是以1加权,不知道有没有其它差别。
void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth,
                Size ksize, Point anchor,
                bool normalize, int borderType )
{
    Mat src = _src.getMat();//获得处理图像
    //创建输出OutputArray _dst
    int sdepth = src.depth(), cn = src.channels();//获取图像的深度和通道数
    if( ddepth < 0 )//这边均值滤波传值过来的时候是-1小于0
        ddepth = sdepth;
    _dst.create( src.size(), CV_MAKETYPE(ddepth, cn) );//CV_MAKETYPE创建图像类型根据深度和通道数,这句是创建_dst
    Mat dst = _dst.getMat();//通过OutputArray得到Mat类型
    //BORDER_CONSTANT边界类型,opencv根据边界类型进行不同的插值运算来扩展边界
/*
不同的边界类型, '|'表示图像边界
* BORDER_REPLICATE:     aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT:       fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101:   gfedcb|abcdefgh|gfedcba
* BORDER_WRAP:          cdefgh|abcdefgh|abcdefg       
* BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii  使用特定的'i'
*/
    if( borderType != BORDER_CONSTANT && normalize )//normalize均值滤波调用的时候是true,borderType=BORDER_DEFAULT默认值为
                                                                                           //BORDE R_REFLECT_101
    {
        if( src.rows == 1 )//如果源图像的行为1则滤波窗口的高度为1
            ksize.height = 1;
        if( src.cols == 1 )//如果源图像的列为1则滤波窗口的宽度为1
            ksize.width = 1;
    }
    //创建盒子滤波 返回滤波引擎,不管创建什么滤波都返回滤波引擎,工厂模式是由滤波引擎可以创建各种滤波,这个是什么模式呢?
    Ptr<FilterEngine> f = createBoxFilter( src.type(), dst.type(),
                        ksize, anchor, normalize, borderType );
    f->apply( src, dst );//virtual void apply( const Mat& src, Mat& dst,const Rect& srcRoi=Rect(0,0,-1,-1),
                          //Point dstOfs=Point(0,0),bool isolated=false);可以控制滤波图像的大小,这边是全部滤波
}
下面是创建盒子滤波
cv::Ptr<cv::FilterEngine> cv::createBoxFilter( int srcType, int dstType, Size ksize,
                    Point anchor, bool normalize, int borderType )
{
    int sdepth = CV_MAT_DEPTH(srcType);//由深度跟通道数可以确定图像类型,这边由类型确定深度,下面是确定通道数
    int cn = CV_MAT_CN(srcType), sumType = CV_64F;//定义类型为64位浮点数
    /*在types_c.h中有
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
*/
    if( sdepth < CV_32S && (!normalize ||
        ksize.width*ksize.height <= (sdepth == CV_8U ? (1<<23) :
            sdepth == CV_16U ? (1 << 15) : (1 << 16))) )
        sumType = CV_32S;//如果图像的深度不是32位或者64位的浮点型并且不归一化或者滤波窗口的面积
    sumType = CV_MAKETYPE( sumType, cn );//这边也不是很清楚这么写的目的,感觉完全就是控制像素类型不是64位浮点就是32位int类型???,也就是CV_8U,CV_16U,CV_16S都对应CV_32S,其余对应CV_64F?

    Ptr<BaseRowFilter> rowFilter = getRowSumFilter(srcType, sumType, ksize.width, anchor.x );
    Ptr<BaseColumnFilter> columnFilter = getColumnSumFilter(sumType,
        dstType, ksize.height, anchor.y, normalize ? 1./(ksize.width*ksize.height) : 1);

    return Ptr<FilterEngine>(new FilterEngine(Ptr<BaseFilter>(0), rowFilter, columnFilter,
           srcType, dstType, sumType, borderType ));
}
主要的就是两步getRowSumFilter跟getColumnSumFilter
cv::Ptr<cv::BaseRowFilter> cv::getRowSumFilter(int srcType, int sumType, int ksize, int anchor)
{
    int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(sumType);
    CV_Assert( CV_MAT_CN(sumType) == CV_MAT_CN(srcType) );
    //要进行滤波的像素点如果这边设置小于0的话就是滤波窗口的一半,也就是滤波窗体的中心,这边滤波窗体一般设置为奇数
    if( anchor < 0 )
        anchor = ksize/2;
    //对于不同的图像像素值类型计算一行的像素和
    if( sdepth == CV_8U && ddepth == CV_32S )
        return Ptr<BaseRowFilter>(new RowSum<uchar, int>(ksize, anchor));
    if( sdepth == CV_8U && ddepth == CV_64F )
        return Ptr<BaseRowFilter>(new RowSum<uchar, double>(ksize, anchor));
    if( sdepth == CV_16U && ddepth == CV_32S )
        return Ptr<BaseRowFilter>(new RowSum<ushort, int>(ksize, anchor));
    if( sdepth == CV_16U && ddepth == CV_64F )
        return Ptr<BaseRowFilter>(new RowSum<ushort, double>(ksize, anchor));
    if( sdepth == CV_16S && ddepth == CV_32S )
        return Ptr<BaseRowFilter>(new RowSum<short, int>(ksize, anchor));
    if( sdepth == CV_32S && ddepth == CV_32S )
        return Ptr<BaseRowFilter>(new RowSum<int, int>(ksize, anchor));
    if( sdepth == CV_16S && ddepth == CV_64F )
        return Ptr<BaseRowFilter>(new RowSum<short, double>(ksize, anchor));
    if( sdepth == CV_32F && ddepth == CV_64F )
        return Ptr<BaseRowFilter>(new RowSum<float, double>(ksize, anchor));
    if( sdepth == CV_64F && ddepth == CV_64F )
        return Ptr<BaseRowFilter>(new RowSum<double, double>(ksize, anchor));

    CV_Error_( CV_StsNotImplemented,
        ("Unsupported combination of source format (=%d), and buffer format (=%d)",
        srcType, sumType));

    return Ptr<BaseRowFilter>(0);
}
创建一行的像素和操作如下:
这个继承对1维数据处理的基类,实现滤波操作,这边的参数const uchar* src, uchar* dst, int width, int cn怎么传的呢???望有人解答一下
void operator()(const uchar* src, uchar* dst, int width, int cn)
    {
        const T* S = (const T*)src;//将src转换到对应的T模板类型
        ST* D = (ST*)dst;//dst转换到对应的ST模板类型
        int i = 0, k, ksz_cn = ksize*cn;
        
        width = (width - 1)*cn;
        for( k = 0; k < cn; k++, S++, D++ )
        {
            ST s = 0;
            for( i = 0; i < ksz_cn; i += cn )
                s += S[i];
            D[0] = s;
            for( i = 0; i < width; i += cn )
            {
                s += S[i + ksz_cn] - S[i];
                D[i+cn] = s;
            }
        }
    }

好了,就先写到这,其实最核心的东西没有写,自己也不甚理解,望有人给予一定的解惑,谢谢。

posted @ 2013-01-08 23:48  越影&逐日而行  阅读(770)  评论(0编辑  收藏  举报