当前位置: 首页 > article >正文

图像卷积OpenCV C/C++ 核心操作

图像卷积:OpenCV C++ 核心操作

图像卷积是图像处理和计算机视觉领域最基本且最重要的操作之一。它通过一个称为卷积核(或滤波器)的小矩阵,在输入图像上滑动,并对核覆盖的图像区域执行元素对应相乘后求和的运算,从而生成输出图像的对应像素值。卷积可以用于实现模糊、锐化、边缘检测、降噪等多种效果。

本文将介绍如何在 C++/OpenCV 中执行图像卷积操作。


卷积的基本原理 🧠

给定一个输入图像 I I I 和一个卷积核 K K K(通常是一个小尺寸的奇数正方形矩阵,如 3 × 3 3 \times 3 3×3 5 × 5 5 \times 5 5×5),输出图像 O O O 的每个像素 ( x , y ) (x, y) (x,y) 的值是通过以下方式计算的:

O ( x , y ) = ( I ∗ K ) ( x , y ) = ∑ i = − m m ∑ j = − n n I ( x − i , y − j ) ⋅ K ( i , j ) O(x, y) = (I * K)(x, y) = \sum_{i=-m}^{m} \sum_{j=-n}^{n} I(x-i, y-j) \cdot K(i, j) O(x,y)=(IK)(x,y)=i=mmj=nnI(xi,yj)K(i,j)

其中, K K K 的尺寸是 ( 2 m + 1 ) × ( 2 n + 1 ) (2m+1) \times (2n+1) (2m+1)×(2n+1)。简单来说,就是将卷积核翻转(在实际计算中,许多库包括OpenCV默认使用的已经是“相关”操作,即不进行翻转,或者说卷积核已经预先翻转好了),然后将其中心对准输入图像的当前像素。接着,将核的每个元素与其覆盖的图像像素相乘,最后将所有乘积相加,得到输出图像中该像素的值。

锚点 (Anchor Point):卷积核中用于对齐图像当前处理像素的点。默认情况下,它是核的中心。

边界处理 (Border Handling):当卷积核的某些部分移动到图像边界之外时,需要一种策略来填充这些“虚拟”像素。常见的边界处理方法有:

  • BORDER_CONSTANT: 用常数值填充。
  • BORDER_REPLICATE: 复制边界像素。
  • BORDER_REFLECT: 反射边界像素。
  • BORDER_WRAP: 环绕式填充。
  • BORDER_DEFAULT (或 BORDER_REFLECT_101): OpenCV 中的默认方法,与 BORDER_REFLECT 类似,但不复制边界像素本身。

使用 OpenCV cv::filter2D 进行卷积

OpenCV 提供了 cv::filter2D 函数来实现任意线性的图像滤波(即卷积)。

函数原型

void cv::filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor = Point(-1,-1), double delta = 0, int borderType = BORDER_DEFAULT);
  • src: 输入图像。
  • dst: 输出图像,与输入图像具有相同的尺寸和通道数。
  • ddepth: 输出图像的期望深度(例如 CV_8U, CV_16S, CV_32F 等)。通常设置为 -1 表示输出图像与输入图像具有相同的深度。如果进行浮点数运算或者结果可能超出原类型范围(如边缘检测的梯度),则可能需要指定更深的类型(如 CV_16SCV_32F),之后再转换回 CV_8U
  • kernel: 卷积核(一个单通道的浮点数矩阵)。
  • anchor: 核内的锚点位置。Point(-1, -1) 表示锚点位于核的中心。
  • delta: 在将结果存储到 dst 之前,可选地加到每个滤波后像素上的值。默认为0。
  • borderType: 像素外推方法,用于处理图像边界。

C++ OpenCV 代码示例 💻

下面的代码演示了如何定义一个简单的平均模糊核和一个锐化核,并使用 cv::filter2D 将它们应用于图像。

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>int main(int argc, char** argv) {// 检查命令行参数if (argc != 2) {std::cout << "用法: " << argv[0] << " <图片路径>" << std::endl;return -1;}// 1. 加载源图像cv::Mat srcImage = cv::imread(argv[1], cv::IMREAD_COLOR);if (srcImage.empty()) {std::cerr << "错误: 无法加载图像 " << argv[1] << std::endl;return -1;}// 2. 定义卷积核// 示例1: 平均模糊核 (3x3)cv::Mat blurKernel = cv::Mat::ones(3, 3, CV_32F) / 9.0f; // 归一化// 示例2: 锐化核 (3x3)cv::Mat sharpenKernel = (cv::Mat_<float>(3,3) <<0, -1,  0,-1,  5, -1,0, -1,  0);// 示例3: 简单的边缘检测核 (Sobel X 近似)cv::Mat edgeKernel = (cv::Mat_<float>(3,3) <<-1, 0, 1,-2, 0, 2,-1, 0, 1);// 3. 应用卷积cv::Mat blurredImage, sharpenedImage, edgeImage;int ddepth = -1; // 输出图像深度与输入图像相同cv::Point anchor = cv::Point(-1, -1); // 锚点在核中心double delta = 0; // 无偏移量int borderType = cv::BORDER_DEFAULT; // 默认边界处理// 应用模糊核cv::filter2D(srcImage, blurredImage, ddepth, blurKernel, anchor, delta, borderType);// 应用锐化核cv::filter2D(srcImage, sharpenedImage, ddepth, sharpenKernel, anchor, delta, borderType);// 应用边缘检测核// 对于可能产生负值或需要更大动态范围的核 (如梯度算子),最好使用更深的类型// 然后再转换回 CV_8U 进行显示cv::Mat edgeImageFloat;cv::filter2D(srcImage, edgeImageFloat, CV_32F, edgeKernel, anchor, delta, borderType);cv::convertScaleAbs(edgeImageFloat, edgeImage); // 转换为 CV_8U 并取绝对值// 4. 显示图像cv::imshow("原始图像", srcImage);cv::imshow("模糊图像 (自定义核)", blurredImage);cv::imshow("锐化图像 (自定义核)", sharpenedImage);cv::imshow("边缘检测图像 (自定义核)", edgeImage);cv::waitKey(0); // 等待按键cv::destroyAllWindows(); // 关闭所有窗口return 0;
}

代码解释 🧐

  1. 包含头文件
    • opencv2/imgproc.hpp: 包含了图像处理函数,核心是 cv::filter2D
    • opencv2/highgui.hpp: 用于图像的加载、显示。
    • iostream: 用于控制台输出。
  2. 加载图像:使用 cv::imread() 加载。
  3. 定义卷积核
    • blurKernel: 一个 3 × 3 3 \times 3 3×3 的矩阵,所有元素都是 1 / 9 1/9 1/9。这会计算邻域像素的平均值,从而实现模糊效果。cv::Mat::ones(3, 3, CV_32F) 创建一个所有元素为1的 3 × 3 3 \times 3 3×3 浮点数矩阵,然后除以9进行归一化(确保图像整体亮度不变)。
    • sharpenKernel: 一个 3 × 3 3 \times 3 3×3 的矩阵,通过增强中心像素与周围像素的差异来锐化图像。
    • edgeKernel: 一个近似 Sobel X 方向的边缘检测核,用于突出垂直边缘。
    • 注意:卷积核通常定义为 CV_32F (32位浮点数) 类型。
  4. 应用卷积 (cv::filter2D)
    • 对每个定义的核,调用 cv::filter2D
    • ddepth = -1 表示输出图像与输入图像有相同的位深度。
    • 对于 edgeKernel,我们首先将结果存储在 CV_32F 类型的 edgeImageFloat 中,因为梯度计算可能产生负值或超出 CV_8U (0-255) 范围的值。然后,使用 cv::convertScaleAbs 将其转换为 CV_8U 类型以便显示,该函数会取绝对值并进行适当缩放。
  5. 显示图像:使用 cv::imshow() 显示结果。

编译与运行 ⚙️

编译命令示例 (Linux/macOS):

g++ image_convolution.cpp -o image_convolution_app `pkg-config --cflags --libs opencv4` -std=c++11

(如果你的 pkg-config 配置的是 opencv 而不是 opencv4,请相应修改。-std=c++11 或更高版本均可。)

运行命令:

./image_convolution_app <你的图片路径.jpg>

预定义的 OpenCV 滤波函数 💡

虽然 cv::filter2D 非常灵活,可以应用任何自定义核,但 OpenCV 也为许多常见的滤波操作提供了预定义的、高度优化的函数,例如:

  • cv::blur(): 均值模糊 (类似于我们示例中的 blurKernel)。
  • cv::GaussianBlur(): 高斯模糊,最常用的模糊方法之一。
  • cv::medianBlur(): 中值模糊,对去除椒盐噪声特别有效。
  • cv::Sobel(): 计算 Sobel 导数,用于边缘检测。
  • cv::Laplacian(): 计算拉普拉斯算子,也可用于边缘检测和锐化。
  • cv::Scharr(): Scharr 滤波器,有时比 Sobel 提供更精确的梯度方向。

在实际应用中,如果存在预定义的函数,通常推荐使用它们,因为它们可能经过了针对性的优化。但理解 cv::filter2D 的工作原理对于掌握图像滤波和设计自定义效果至关重要。


总结 🏁

图像卷积是图像处理中的一项基础且强大的技术。通过 OpenCV 的 cv::filter2D 函数,我们可以方便地对图像应用自定义的卷积核,实现从简单的模糊、锐化到复杂的边缘检测等多种效果。理解卷积的原理和 cv::filter2D 的使用,将为更高级的图像分析和计算机视觉任务打下坚实的基础。

相关文章:

图像卷积OpenCV C/C++ 核心操作

图像卷积&#xff1a;OpenCV C 核心操作 图像卷积是图像处理和计算机视觉领域最基本且最重要的操作之一。它通过一个称为卷积核&#xff08;或滤波器&#xff09;的小矩阵&#xff0c;在输入图像上滑动&#xff0c;并对核覆盖的图像区域执行元素对应相乘后求和的运算&#xff…...

LiveGBS作为下级平台GB28181国标级联2016|2022对接海康大华宇视华为政务公安内网等GB28181国标平台查看级联状态及会话

LiveGBS作为下级平台GB28181国标级联2016|2022对接海康大华宇视华为政务公安内网等GB28181国标平台查看级联状态及会话 1、GB/T28181级联概述2、搭建GB28181国标流媒体平台3、获取上级平台接入信息3.1、向下级提供信息3.2、上级国标平台添加下级域3.3、接入LiveGBS示例 4、配置…...

leetcode17.电话号码的字母组合:字符串映射与回溯的巧妙联动

一、题目深度解析与字符映射逻辑 题目描述 给定一个仅包含数字 2-9 的字符串 digits&#xff0c;返回所有它能表示的字母组合。数字与字母的映射关系如下&#xff08;与电话按键相同&#xff09;&#xff1a; 2: "abc", 3: "def", 4: "ghi", …...

Gartner《2025 年软件工程规划指南》报告学习心得

一、引言 软件工程领域正面临着前所未有的变革与挑战。随着生成式人工智能(GenAI)等新兴技术的涌现、市场环境的剧烈动荡以及企业对软件工程效能的更高追求,软件工程师们必须不断适应和拥抱变化,以提升自身竞争力并推动业务发展。Gartner 公司发布的《2025 年软件工程规划…...

数据库 | 使用timescaledb和大模型进行数据分析

时序数据库&#xff1a;timescaledb 大模型&#xff1a;通义千问2.5 对话开始前提示词&#xff1a; 我正在做数据分析&#xff0c;以下是已知信息: 数据库:timescaledb&#xff0c;表名&#xff1a;dm_tag_value&#xff0c;tag_name列是位号名&#xff0c;app_time列是时间,…...

快速阅读源码

Doxygen 轻松生成包含类图、调用关系图的 HTML 和 PDF 文档, Graphviz 可以用来生成类图、调用图 sudo apt-get install doxygen graphviz brew install doxygen graphviz#HTML 文档&#xff1a; open docs/html/index.html一、Doxyfile配置: Doxyfile 文件 doxygen Doxyfile P…...

linux创建虚拟网卡和配置多ip

1.展示当前网卡信息列表&#xff1a; linux上&#xff1a; ip a ifconfigwindows上&#xff1a; ipconfig 2.创建虚拟网卡对&#xff1a; sudo ip link add name veth0 type veth peer name veth1 在 ip link add 命令中&#xff0c;type 参数可以指定多种虚拟网络设备类型&…...

Java Class类文件结构

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…...

AI问答-Vue3+TS:reactive创建一个响应式数组,用一个新的数组对象来替换它,同时保持响应性

在 Vue 3 中&#xff0c;当你使用 reactive 创建一个响应式数组后&#xff0c;如果你想用一个新的数组对象来替换它&#xff0c;同时保持响应性&#xff0c;有几种方法可以实现 方法一&#xff1a;直接替换整个数组&#xff08;推荐&#xff09; import { reactive } from vu…...

quasar electron mode如何打包无边框桌面应用程序

预览 开源项目Tokei Kun 一款简洁的周年纪念app&#xff0c;现已发布APK&#xff08;安卓&#xff09;和 EXE&#xff08;Windows&#xff09; 项目仓库地址&#xff1a;Github Repo 应用下载链接&#xff1a;Github Releases Preparation for Electron quasar dev -m elect…...

【HW系列】—Windows日志与Linux日志分析

文章目录 一、Windows日志1. Windows事件日志2. 核心日志类型3. 事件日志分析实战详细分析步骤 二、Linux日志1. 常见日志文件2. 关键日志解析3. 登录爆破检测方法日志分析核心要点 一、Windows日志 1. Windows事件日志 介绍&#xff1a;记录系统、应用程序及安全事件&#x…...

VIN码识别解析接口如何用C#进行调用?

一、什么是VIN码识别解析接口&#xff1f; VIN码不仅是车辆的“身份证”&#xff0c;更是连接制造、销售、维修、保险、金融等多个环节的数字纽带。而VIN码查询API&#xff0c;正是打通这一链条的关键工具。 无论是汽车电商平台、二手车商、维修厂&#xff0c;还是保险公司、金…...

动态规划之网格图模型(一)

文章目录 动态规划之网格图模型&#xff08;一&#xff09;LeetCode 64. 最小路径和思路Golang 代码 LeetCode 62. 不同路径思路Golang 代码 LeetCode 63. 不同路径 II思路Golang 代码 LeetCode 120. 三角形最小路径和思路Golang 代码 LeetCode 3393. 统计异或值为给定值的路径…...

PCB设计实践(三十)地平面完整性

在高速数字电路和混合信号系统设计中&#xff0c;地平面完整性是决定PCB性能的核心要素之一。本文将从电磁场理论、信号完整性、电源分配系统等多个维度深入剖析地平面设计的关键要点&#xff0c;并提出系统性解决方案。 一、地平面完整性的电磁理论基础 电流回流路径分析 在PC…...

x86_64-apple-ios-simulator 错误

Could not find module ImagePicker for target x86_64-apple-ios-simulator; found: arm64, arm64-apple-ios-simulator 解决方案一 添加 arm64。 搜索 Excluded Architectures &#xff0c;添加arm64 解决方案二 在Podfild中&#xff0c;添加佐料。在文件的最下方添加如…...

使用ray扩展python应用之流式处理应用

流式处理就是数据一来&#xff0c;咱们就得赶紧处理&#xff0c;不能攒批再算。这里的实时不是指瞬间完成&#xff0c;而是要在数据产生的那一刻&#xff0c;或者非常接近那个时间点&#xff0c;就做出响应。这种处理方式&#xff0c;我们称之为流式处理。 流式处理的应用场景…...

IP证书的作用与申请全解析:从安全验证到部署实践

在网络安全领域&#xff0c;IP证书&#xff08;IP SSL证书&#xff09;作为传统域名SSL证书的补充方案&#xff0c;专为公网IP地址提供HTTPS加密与身份验证服务。本文将从技术原理、应用场景、申请流程及部署要点四个维度&#xff0c;系统解析IP证书的核心价值与操作指南。 一…...

第四十一天打卡

简单CNN 知识回顾 数据增强 卷积神经网络定义的写法 batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据 特征图&#xff1a;只有卷积操作输出的才叫特征图 调度器&#xff1a;直接修改基础学习率 卷积操作常见流程如下&#xff1a; 1. 输入 → 卷积层 →…...

C++中指针常量和常量指针的区别

C中指针常量和常量指针的区别 前言 在 C/C 编程中&#xff0c;指针是一个非常重要的概念&#xff0c;而指针常量和常量指针又是指针的两种特殊形式&#xff0c;它们在实际开发中有着不同的应用场景和语义&#xff0c;理解它们的区别对于编写高质量的代码至关重要。本文将详细…...

深入解析向量数据库:基本原理与主流实现

向量数据库&#xff08;Vector Database&#xff09;是专门用于存储和检索高维向量的数据库系统。近年来&#xff0c;随着机器学习和深度学习的发展&#xff0c;文本、图像、音频等非结构化数据常被转换为向量表示&#xff0c;用于语义搜索和推荐等场景。这篇博客将面向 Java/P…...

VectorNet:自动驾驶中的向量魔法

在自动驾驶的世界里&#xff0c;车辆需要像超级英雄一样&#xff0c;拥有“透视眼”和“预知未来”的能力&#xff0c;才能在复杂的交通环境中安全行驶。今天&#xff0c;我们要介绍一个神奇的工具——VectorNet&#xff0c;它就像是给自动驾驶车辆装上了一双智能的眼睛&#x…...

PostgreSQL性能监控双雄:深入解析pg_stat_statements与pg_statsinfo

在PostgreSQL的运维和优化工作中&#xff0c;性能监控工具的选择直接关系到问题定位的效率和数据库的稳定性。今天我们将深入探讨两款核心工具&#xff1a;pg_stat_statements&#xff08;SQL执行统计&#xff09;和pg_statsinfo&#xff08;系统级监控&#xff09;&#xff0c…...

【Linux系列】Linux/Unix 系统中的 CPU 使用率

博客目录 多核处理器时代的 CPU 使用率计算为什么要这样设计&#xff1f; 解读实际案例&#xff1a;268.76%的 CPU 使用率性能分析的意义 相关工具与监控实践1. top 命令2. htop 命令3. mpstat 命令4. sar 命令 实际应用场景容量规划性能调优故障诊断 深入理解&#xff1a;CPU …...

C++语法系列之模板进阶

前言 本次会介绍一下非类型模板参数、模板的特化(特例化)和模板的可变参数&#xff0c;不是最开始学的模板 一、非类型模板参数 字面意思,比如&#xff1a; template<size_t N 10> 或者 template<class T,size_t N 10>比如&#xff1a;静态栈就可以用到&#…...

基于图神经网络的自然语言处理:融合LangGraph与大型概念模型的情感分析实践

在企业数字化转型进程中&#xff0c;非结构化文本数据的处理与分析已成为核心技术挑战。传统自然语言处理方法在处理客户反馈、社交媒体内容和内部文档等复杂数据集时&#xff0c;往往难以有效捕获文本间的深层语义关联和结构化关系。大型概念模型&#xff08;Large Concept Mo…...

R 语言科研绘图 --- 热力图-汇总

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

基于DFT码本的波束方向图生成MATLAB实现

基于DFT码本的波束方向图生成MATLAB实现&#xff0c;包含参数配置、方向图生成和可视化模块&#xff1a; %% 基于DFT码本的波束方向图生成 clc; clear; close all;%% 参数配置 params struct(...N, 8, % 阵元数d, 0.5, % 阵元间距(λ/2)theta_sc…...

vBulletin未认证API方法调用漏洞(CVE-2025-48827)

免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…...

解决访问网站提示“405 很抱歉,由于您访问的URL有可能对网站造成安全威胁,您的访问被阻断”问题

一、问题描述 本来前几天都可以正常访问的网站&#xff0c;但是今天当我们访问网站的时候会显示“405 很抱歉&#xff0c;由于您访问的URL有可能对网站造成安全威胁&#xff0c;您的访问被阻断。您的请求ID是&#xff1a;XXXX”&#xff0c;而不能正常的访问网站&#xff0c;如…...

FeignClient发送https请求时的证书验证原理分析

背景 微服务之间存在调用关系&#xff0c;且部署为 SSL 协议时&#xff0c;Feignt 请求报异常&#xff1a; Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find vali…...