【OpenCV • c++】图像平滑处理(2) —— 方框滤波 | 盒滤波 | 源码分析

前言

  前文我们了解了什么是图像平滑处理、图像滤波、邻域算子与线性邻域滤波、以及如何使用方框滤波,本文我们来分析一下方框滤波的源码。

一、方框滤波

 	void boxFilter(InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1, -1), boolnormalize=true, int borderType=BORDEX_DEFAULT)

  其中,第一个参数表示输入的原图像,第二个参数表示目标图像,需要和原图像一样尺寸和类型,第三个参数表示输出图像的深度,-1代表使用原深度,即src.depth(),第四个参数表示 Size 类型的 ksize ,内核的大小。一般用 Size(w, h) 表示内核的大小,其中 w 为像素宽度,h 为像素的高度。Size(3, 3)的核大小。第五个参数表示锚点(平滑的那个点)。默认是 Point(-1, -1)。如果这个点的坐标是负值的话,就取核的中心为锚点。第六个参数六表示内核是否被其区域归一化了,第七个参数表示用于推断图像外部像素的某种边界模式。

代码演示

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;

int main()
{
    // 读取输入图像
    Mat src = imread("D://cc.jpg", IMREAD_COLOR);
    if (src.empty())
    {
        std::cout << "无法读取图像" << std::endl;
        return -1;
    }

    // 创建输出矩阵
    Mat dst;

    // 应用方框滤波器
    int ddepth = -1;  // 使用与输入图像相同的深度
    Size ksize(3, 3); // 内核的大小
    Point anchor(-1, -1); // 内核中的锚点
    bool normalize = true; // 归一化内核
    int borderType = BORDER_DEFAULT; // 边界类型

    boxFilter(src, dst, ddepth, ksize, anchor, normalize, borderType);

    // 显示结果
    imshow("输入", src);
    imshow("输出", dst);
    waitKey(0);

    return 0;
}

在这里插入图片描述

二、源码分析

//方框滤波器基类生成函数
Ptr<FilterEngine> 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;  // 获取输入矩阵的通道数,并设置默认的累加类型为CV_64F
    if (sdepth == CV_8U && CV_MAT_DEPTH(dstType) == CV_8U &&
        ksize.width * ksize.height <= 256)
        sumType = CV_16U;  // 如果输入矩阵和输出矩阵的深度都是CV_8U,并且滤波核的大小不超过256,则将累加类型设置为CV_16U
    else if (sdepth <= CV_32S && (!normalize ||
        ksize.width * ksize.height <= (sdepth == CV_8U ? (1 << 23) :
            sdepth == CV_16U ? (1 << 15) : (1 << 16))))
        sumType = CV_32S;  // 如果输入矩阵的深度小于等于CV_32S,并且滤波核的大小不超过一定阈值,则将累加类型设置为CV_32S
    sumType = CV_MAKETYPE(sumType, cn);  // 根据累加类型和通道数创建累加矩阵的数据类型

    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 makePtr<FilterEngine>(Ptr<BaseFilter>(), rowFilter, columnFilter,
        srcType, dstType, sumType, borderType);  // 创建FilterEngine对象并返回
}

//方框滤波器实现
void boxFilter(InputArray _src, OutputArray _dst, int ddepth,
    Size ksize, Point anchor,
    bool normalize, int borderType)
{
    Mat src = _src.getMat();  // 获取输入矩阵
    int sdepth = src.depth(), cn = src.channels();
    if (ddepth < 0)
        ddepth = sdepth;
    _dst.create(src.size(), CV_MAKETYPE(ddepth, cn));  // 创建输出矩阵
    Mat dst = _dst.getMat();
    if (borderType != BORDER_CONSTANT && normalize && (borderType & BORDER_ISOLATED) != 0)
    {
        if (src.rows == 1)
            ksize.height = 1;  // 如果输入矩阵的行数为1,则将滤波核的高度设置为1
        if (src.cols == 1)
            ksize.width = 1;  // 如果输入矩阵的列数为1,则将滤波核的宽度设置为1
    }

    Point ofs;  // 偏移量
    Size wsz(src.cols, src.rows);  // 窗口大小
    if (!(borderType & BORDER_ISOLATED))
        src.locateROI(wsz, ofs);  // 定位输入矩阵的感兴趣区域(ROI)

    Ptr<FilterEngine> f = createBoxFilter(src.type(), dst.type(),
        ksize, anchor, normalize, borderType);  // 创建方框滤波器

    f->apply(src, dst, wsz, ofs);  // 应用方框滤波器
}

  通过阅读方框滤波的部分源码,可以发现,boxFilter()函数在调用后先是进行了一系列的判断,确定图像属性,再通过调用createBoxFilter()函数来创建方框滤波器。

  • 🚀 个人简介:CSDN「博客新星」TOP 10 , C/C++ 领域新星创作者
  • 💟 作    者:锡兰_CC ❣️
  • 📝 专    栏:【OpenCV • c++】计算机视觉
  • 🌈 若有帮助,还请关注➕点赞➕收藏,不行的话我再努努力💪💪💪

其他

更多专栏订阅推荐:

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-05-02 17:16:20       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-02 17:16:20       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-02 17:16:20       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-02 17:16:20       20 阅读

热门阅读

  1. 频繁的FullGC问题如何排查和解决?

    2024-05-02 17:16:20       9 阅读
  2. boost::asio::ip::tcp::acceptor::reuse_address

    2024-05-02 17:16:20       8 阅读
  3. 网络相关概念

    2024-05-02 17:16:20       10 阅读
  4. 笨蛋学C++【C++基础第十弹】

    2024-05-02 17:16:20       10 阅读
  5. 类与对象(中):类的6个默认成员函数

    2024-05-02 17:16:20       10 阅读
  6. 达梦数据库使用-外部表

    2024-05-02 17:16:20       10 阅读
  7. C++ P1115 最大子段和

    2024-05-02 17:16:20       12 阅读
  8. C++ -- Array 学习

    2024-05-02 17:16:20       13 阅读
  9. C++ 类对象初始化

    2024-05-02 17:16:20       9 阅读
  10. SQL中为什么不要使用1=1?

    2024-05-02 17:16:20       12 阅读
  11. 知识图谱与大语言模型的协同(RAG)——MindMap

    2024-05-02 17:16:20       12 阅读
  12. 23种设计模式

    2024-05-02 17:16:20       11 阅读