使用 OpenCV 函数filter2D()创建您自己的线性过滤器

理论

笔记

以下解释属于Bradski 和 Kaehler 所著的《Learning OpenCV》一书。

相关性

从非常广泛的意义上讲,相关性是图像的每个部分与运算符(核)之间的操作。

什么是内核?

核本质上是一个固定大小的数值系数数组,以及该数组中的锚点,通常位于中心。

与内核的关联如何起作用?

假设你想知道图像中特定位置的结果值。相关性值按以下方式计算:

  1. 将核锚点放置在确定像素的顶部,核的其余部分覆盖图像中相应的局部像素。
  2. 将核系数与相应的图像像素值相乘,然后对结果求和。
  3. 将结果放置到输入图像中锚点的位置。
  4. 通过扫描整个图像上的内核,对所有像素重复该过程。

将上述过程以方程形式表达,可得:

幸运的是,OpenCV 为您提供了函数filter2D(),因此您不必编写所有这些操作的代码。

这个程序是做什么的?

  • 加载图片
  • 执行规范化盒式过滤器。例如,对于大小为s我是埃=3,内核将是:

该程序将使用大小为 3、5、7、9 和 11 的内核执行过滤操作。

  • 过滤器输出(每个内核)将在 500 毫秒内显示

C++代码
 

教程代码显示如下。

您也可以从此处下载


#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;

int main ( int argc, char** argv )
{
    // Declare variables
    Mat src, dst;

    Mat kernel;
    Point anchor;
    double delta;
    int ddepth;
    int kernel_size;
    const char* window_name = "filter2D Demo";

    const char* imageName = argc >=2 ? argv[1] : "lena.jpg";

    // Loads an image
    src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image

    if( src.empty() )
    {
        printf(" Error opening image\n");
        printf(" Program Arguments: [image_name -- default lena.jpg] \n");
        return EXIT_FAILURE;
    }

    // Initialize arguments for the filter
    anchor = Point( -1, -1 );
    delta = 0;
    ddepth = -1;

    // Loop - Will filter the image with different kernel sizes each 0.5 seconds
    int ind = 0;
    for(;;)
    {
        // Update kernel size for a normalized box filter
        kernel_size = 3 + 2*( ind%5 );
        kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);

        // Apply filter
        filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
        imshow( window_name, dst );

        char c = (char)waitKey(500);
        // Press 'ESC' to exit the program
        if( c == 27 )
        { break; }

        ind++;
    }

    return EXIT_SUCCESS;
}

解释

加载图像

C++

    const char* imageName = argc >=2 ? argv[1] : "lena.jpg";

    // Loads an image
    src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image

    if( src.empty() )
    {
        printf(" Error opening image\n");
        printf(" Program Arguments: [image_name -- default lena.jpg] \n");
        return EXIT_FAILURE;
    }

 

初始化参数

C++

    // Initialize arguments for the filter
    anchor = Point( -1, -1 );
    delta = 0;
    ddepth = -1;


C++JavaPython

执行无限循环,更新内核大小并将线性滤波器应用于输入图像。让我们更详细地分析一下:

  • 首先我们定义过滤器要使用的内核。它如下:
        // Update kernel size for a normalized box filter
        kernel_size = 3 + 2*( ind%5 );
        kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);

第一行是将kernel_size更新为范围内的奇数值:[3,11]第二行实际上是通过将其值设置为填充有1′s并通过将其除以元素数量来对其进行标准化。

  • 设置内核后,我们可以使用函数filter2D()生成过滤器:
        // Apply filter
        filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );

  • 参数表示:
    • src:源图像
    • dst:目标图像
    • ddepth : dst的深度。负值(例如−1)表示深度与源相同。
    • kernel:要通过图像扫描的内核
    • anchor:锚点相对于其核的位置。位置Point(-1, -1)默认表示中心。
    • delta:在相关过程中要添加到每个像素的值。默认情况下,它是0
    • BORDER_DEFAULT:我们默认使用这个值(更多细节请见后续教程)
  • 我们的程序将实现一个while循环,每 500 毫秒,我们的过滤器的内核大小将在指示的范围内更新。

结果

  1. 编译上述代码后,您可以执行它并将图像的路径作为参数。结果应该是一个窗口,其中显示由规范化过滤器模糊的图像。每 0.5 秒内核大小应该会发生变化,如下面的一系列快照所示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值