使用 OpenCV 自定义线性滤波器教程
目标
在本教程中,您将学习如何使用 OpenCV 函数创建您自己的线性过滤器,并理解其背后的数学原理。
本教程详细讲解了如何使用 OpenCV 创建自定义线性滤波器。内容涵盖相关性与内核的理论基础,包括计算公式和锚点概念。提供了完整的 C++ 代码示例,演示了如何加载图像、动态调整内核大小(3 到 11 像素)并应用归一化框筛选器。代码包含详细的参数解释,涉及 filter2D 函数的深度、锚点、增量及边界处理设置。此外,还补充了边界处理类型、性能优化建议以及其他常见算子(如锐化、边缘检测)的实现思路,帮助开发者掌握图像平滑与滤波的核心技术。

在本教程中,您将学习如何使用 OpenCV 函数创建您自己的线性过滤器,并理解其背后的数学原理。
从非常一般的意义上讲,相关性是图像的每个部分与运算符(内核)之间的操作。在图像处理中,我们通常使用卷积或相关运算来提取特征或进行平滑处理。
内核本质上是一个固定大小的数值系数数组,以及该数组中的锚点。该锚点通常位于中心,决定了计算时相对于当前像素的位置。
假设您想知道图像中特定位置的结果值。相关性的值按以下方式计算:
以方程式的形式表示上述过程,我们将得到: $$H(x, y) = \sum_{i=0}^{M_i - 1} \sum_{j=0}^{M_j-1} I(x+i - a_i, y + j - a_j)K(i,j)$$
幸运的是,OpenCV 为您提供了函数 filter2D,因此您不必编写所有这些底层操作。
本示例程序将演示以下功能:
以下是完整的 C++ 代码示例。请确保您的开发环境已正确配置 OpenCV。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// 声明变量
Mat src, dst;
int anchor = -1;
double delta = 0;
int ddepth = -1;
int kernel_size;
const char* window_name = "filter2D 演示";
const char* imageName = (argc >= 2) ? argv[1] : "lena.jpg";
// 加载图像
src = imread(imageName, IMREAD_COLOR);
if (src.empty())
{
printf("打开图像时出错\n");
printf("程序参数:[image_name – default lena.jpg]\n");
return EXIT_FAILURE;
}
// 初始化筛选器的参数
anchor = -1; // 默认中心
delta = 0;
ddepth = -1; // 深度与源相同
// 循环 - 每 0.5 秒过滤一次具有不同内核大小的图像
int ind = 0;
while (true)
{
// 更新规范化框筛选器的内核大小
// 内核大小序列:3, 5, 7, 9, 11
kernel_size = 3 + 2 * (ind % 5);
// 创建归一化内核 (所有值为 1/kernel_size^2)
Mat kernel = Mat::ones(kernel_size, kernel_size, CV_32F) / (float)(kernel_size * kernel_size);
// 应用过滤器
filter2D(src, dst, ddepth, kernel, Point(anchor, anchor), delta, BORDER_DEFAULT);
// 显示结果
imshow(window_name, dst);
// 等待 500 毫秒,如果按下 ESC 则退出
int c = waitKey(500);
if (c == 27) // ESC key
{
break;
}
ind++;
}
return EXIT_SUCCESS;
}
首先检查命令行参数,如果没有提供图片路径,则默认加载 lena.jpg。使用 imread 读取后,必须检查图像是否成功加载 (src.empty()),以避免后续操作崩溃。
Point(-1, -1) 表示中心。dst 的深度。负值(如 -1)表示深度与源图像相同。程序执行一个 while 循环,每 500 毫秒更新一次内核大小。
Mat::ones 创建一个全 1 矩阵,然后除以元素总数进行归一化。这实现了均值滤波效果。filter2D 函数接受源图像、目标图像、深度、内核、锚点、增量和边界类型作为参数。waitKey(500) 暂停 500 毫秒并检测键盘输入。如果检测到 ESC 键 (ASCII 27),则跳出循环结束程序。编译并运行上述代码后,您可以给出图像的路径作为参数。结果应是一个窗口,显示由归一化滤镜模糊的图像。
随着内核大小从 3 增加到 11,图像的模糊程度会逐渐增强。较大的内核意味着更多的像素参与平均计算,从而导致更强烈的平滑效果和更高的计算开销。
filter2D 支持多种边界填充模式,除了默认的 BORDER_DEFAULT,您还可以选择:
BORDER_CONSTANT: 用常数填充边界。BORDER_REPLICATE: 复制最近的边缘像素。BORDER_REFLECT: 镜像反射边缘像素。线性滤波器的计算复杂度与内核大小平方成正比。在处理高分辨率图像或视频流时,过大的内核可能导致帧率下降。建议根据实际需求平衡模糊效果与处理速度。
除了均值滤波,您还可以定义不同的内核来实现其他功能:
通过本教程,您已经掌握了如何使用 OpenCV 的 filter2D 函数自定义线性滤波器。理解内核的构造和归一化原理是进行高级图像处理的基础。您可以在此基础上修改内核权重,探索更多图像增强和特征提取的应用场景。
注:本文档基于 OpenCV 官方文档及经典图像处理理论整理,旨在提供清晰的技术实践指南。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online