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

OpenCV从入门到精通实战(七)——探索图像处理:自定义滤波与OpenCV卷积核

本文主要介绍如何使用Python和OpenCV库通过卷积操作来应用不同的图像滤波效果。主要分为几个步骤:图像的读取与处理、自定义卷积函数的实现、不同卷积核的应用,以及结果的展示。

卷积

在图像处理中,卷积是一种重要的操作,它通过将图像与一个小的矩阵(称为卷积核或滤波器)进行运算来影响图像的各种属性。这种操作可以用于实现模糊、锐化、边缘检测等效果。今天,我们将探讨如何在Python中使用OpenCV库来自定义卷积核,并将其应用于图像处理任务中。

图像的读取与处理

首先,我们需要读取一张图像,并将其转换成灰度图,因为在这个例子中我们将使用灰度图像来简化处理过程:

image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

自定义卷积函数的实现

接下来,我们实现一个名为convolve的函数,该函数接收一个图像和一个卷积核作为输入,并返回卷积后的结果。在这个过程中,我们通过为图像添加边界,然后对每个像素应用卷积核来完成卷积操作:

def convolve(image, kernel):# 输入图像和核的尺寸(iH, iW) = image.shape[:2](kH, kW) = kernel.shape[:2]# 选择pad,卷积后图像大小不变pad = (kW - 1) // 2# 重复最后一个元素,top, bottom, left, rightimage = cv2.copyMakeBorder(image, pad, pad, pad, pad,cv2.BORDER_REPLICATE)output = np.zeros((iH, iW), dtype="float32")# 卷积操作for y in np.arange(pad, iH + pad):for x in np.arange(pad, iW + pad):# 提取每一个卷积区域roi = image[y - pad:y + pad + 1, x - pad:x + pad + 1]# 内积运算k = (roi * kernel).sum()# 保存相应的结果output[y - pad, x - pad] = k# 将得到的结果放缩到[0, 255]output = rescale_intensity(output, in_range=(0, 255))output = (output * 255).astype("uint8")return output

不同卷积核的应用

为了展示不同的图像处理效果,我们定义了几种不同的卷积核:

  • **小模糊(Small Blur)大模糊(Large Blur)**用于创建模糊效果。
  • **锐化(Sharpen)**卷积核可以使图像看起来更清晰。
  • **拉普拉斯(Laplacian)索贝尔(Sobel)**卷积核用于边缘检测。
smallBlur = np.ones((7, 7), dtype="float") * (1.0 / (7 * 7))
largeBlur = np.ones((21, 21), dtype="float") * (1.0 / (21 * 21))
# 尝试不同的卷积核
sharpen = np.array(([0, -1, 0],[-1, 5, -1],[0, -1, 0]), dtype="int")laplacian = np.array(([0, 1, 0],[1, -4, 1],[0, 1, 0]), dtype="int")sobelX = np.array(([-1, 0, 1],[-2, 0, 2],[-1, 0, 1]), dtype="int")sobelY = np.array(([-1, -2, -1],[0, 0, 0],[1, 2, 1]), dtype="int")# 尝试不同结果
kernelBank = (("small_blur", smallBlur),("large_blur", largeBlur),("sharpen", sharpen),("laplacian", laplacian),("sobel_x", sobelX),("sobel_y", sobelY)
)# 更多卷积核...

结果的展示

最后,我们遍历每一个卷积核,将其应用于原始图像,并显示结果:

for (kernelName, kernel) in kernelBank:convoleOutput = convolve(gray, kernel)opencvOutput = cv2.filter2D(gray, -1, kernel)# 展示结果# 分别展示结果cv2.imshow("original", gray)cv2.imshow("{} - convole".format(kernelName), convoleOutput)cv2.imshow("{} - opencv".format(kernelName), opencvOutput)cv2.waitKey(0)cv2.destroyAllWindows()

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以看到卷积核在图像处理中的强大作用,以及如何通过调整卷积核来实现不同的视觉效果。

完整代码

# 导入工具包
from skimage.exposure import rescale_intensity
import numpy as np
import argparse
import cv2def convolve(image, kernel):# 输入图像和核的尺寸(iH, iW) = image.shape[:2](kH, kW) = kernel.shape[:2]# 选择pad,卷积后图像大小不变pad = (kW - 1) // 2# 重复最后一个元素,top, bottom, left, rightimage = cv2.copyMakeBorder(image, pad, pad, pad, pad,cv2.BORDER_REPLICATE)output = np.zeros((iH, iW), dtype="float32")# 卷积操作for y in np.arange(pad, iH + pad):for x in np.arange(pad, iW + pad):# 提取每一个卷积区域roi = image[y - pad:y + pad + 1, x - pad:x + pad + 1]# 内积运算k = (roi * kernel).sum()# 保存相应的结果output[y - pad, x - pad] = k# 将得到的结果放缩到[0, 255]output = rescale_intensity(output, in_range=(0, 255))output = (output * 255).astype("uint8")return output# 指定输入图像
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default="lanpangzi.jpg",help="path to the input image")
args = vars(ap.parse_args())# 分别构建两个卷积核
smallBlur = np.ones((7, 7), dtype="float") * (1.0 / (7 * 7))
largeBlur = np.ones((21, 21), dtype="float") * (1.0 / (21 * 21))# 尝试不同的卷积核
sharpen = np.array(([0, -1, 0],[-1, 5, -1],[0, -1, 0]), dtype="int")laplacian = np.array(([0, 1, 0],[1, -4, 1],[0, 1, 0]), dtype="int")sobelX = np.array(([-1, 0, 1],[-2, 0, 2],[-1, 0, 1]), dtype="int")sobelY = np.array(([-1, -2, -1],[0, 0, 0],[1, 2, 1]), dtype="int")# 尝试不同结果
kernelBank = (("small_blur", smallBlur),("large_blur", largeBlur),("sharpen", sharpen),("laplacian", laplacian),("sobel_x", sobelX),("sobel_y", sobelY)
)# 简单起见,用灰度图来玩
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 遍历每一个核
for (kernelName, kernel) in kernelBank:print("[INFO] applying {} kernel".format(kernelName))convoleOutput = convolve(gray, kernel)# -1 表示深度一致opencvOutput = cv2.filter2D(gray, -1, kernel)# 分别展示结果cv2.imshow("original", gray)cv2.imshow("{} - convole".format(kernelName), convoleOutput)cv2.imshow("{} - opencv".format(kernelName), opencvOutput)cv2.waitKey(0)cv2.destroyAllWindows()

相关文章:

OpenCV从入门到精通实战(七)——探索图像处理:自定义滤波与OpenCV卷积核

本文主要介绍如何使用Python和OpenCV库通过卷积操作来应用不同的图像滤波效果。主要分为几个步骤:图像的读取与处理、自定义卷积函数的实现、不同卷积核的应用,以及结果的展示。 卷积 在图像处理中,卷积是一种重要的操作,它通过…...

Docker核心概念总结

本文只是对 Docker 的概念做了较为详细的介绍,并不涉及一些像 Docker 环境的安装以及 Docker 的一些常见操作和命令。 容器介绍 Docker 是世界领先的软件容器平台,所以想要搞懂 Docker 的概念我们必须先从容器开始说起。 什么是容器? 先来看看容器较为…...

环形缓冲区

什么是环形缓冲区 环形缓冲区,也称为循环缓冲区或环形队列,是一种特殊的FIFO(先进先出)数据结构。它使用一块固定大小的内存空间来缓存数据,并通过两个指针(读指针和写指针)来管理数据的读写。当任意一个指针到达缓冲区末尾时,会自动回绕到缓冲区开头,形成一个"环"。…...

jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js

参考资料: jQuery-Word-Export导出word_jquery.wordexport.js下载-CSDN博客 近期又需要自己做个 Html2Doc 的解决方案,因为客户又不想要 Html2pdf 的下载了,当初还给我费尽心思解决Html转pdf时中文输出的问题(html转pdf文件下载之…...

云服务器部署WebSocket项目

WebSocket是一种在单个TCP连接上进行全双工通信的协议,其设计的目的是在Web浏览器和Web服务器之间进行实时通信(实时Web) WebSocket协议的优点包括: 1. 更高效的网络利用率:与HTTP相比,WebSocket的握手只…...

C#+数据库 实现动态权限设置

将权限信息存储在数据库中,支持动态调整。根据用户所属的角色、特定的功能模块,动态加载权限” 1. 数据库设计 根据这种需求,可以通过以下表设计: 用户表 (Users):存储用户信息。角色表 (Roles):存储角色…...

(原创)Android Studio新老界面UI切换及老版本下载地址

前言 这两天下载了一个新版的Android Studio,发现整个界面都发生了很大改动: 新的界面的一些设置可参考一些博客: Android Studio新版UI常用设置 但是对于一些急着开发的小伙伴来说,没有时间去适应,那么怎么办呢&am…...

Ubuntu24虚拟机-gnome-boxes

推荐使用gnome-boxes, virtualbox构建失败,multipass需要开启防火墙 sudo apt install gnome-boxes创建完毕~...

k8s rainbond centos7/win10 -20241124

参考 https://www.rainbond.com/ 国内一站式云原生平台 对centos7环境支持不太行 [lighthouseVM-16-5-centos ~]$ curl -o install.sh https://get.rainbond.com && bash ./install.sh 2024-11-24 09:56:57 ERROR: Ops! Docker daemon is not running. Start docke…...

SpringBoot+Vue滑雪社区网站设计与实现

【1】系统介绍 研究背景 随着互联网技术的快速发展和冰雪运动的普及,滑雪作为一种受欢迎的冬季运动项目,吸引了越来越多的爱好者。与此同时,社交媒体和在线社区平台的兴起为滑雪爱好者提供了一个交流经验、分享心得、获取信息的重要渠道。滑…...

MySql.2

sql查询语句执行过程 SQL 查询语句的执行过程是一个复杂的过程,涉及多个步骤。以下是典型的关系数据库管理系统 (RDBMS) 中 SQL 查询语句的执行过程概述: 1. ‌客户端发送查询‌ 用户通过 SQL 客户端或应用程序发送 SQL 查询语句给数据库服务器。 2. ‌…...

算法之区间和题目讲解

题干 难度:简单 题目分析 题目要求算出每个指定区间内元素的总和。 然而,区间在输入的最下面,所以按照暴力破解的思路,我们首先要遍历数组,把它的值都存进去。 然后,遍历下面的区间,从索引a…...

价格分类(神经网络)

# 1.导入依赖包 import timeimport torch import torch.nn as nn import torch.optim as optimfrom torch.utils.data import TensorDataset, DataLoader from sklearn.model_selection import train_test_splitimport numpy as np import pandas as pd import matplotlib.pypl…...

对智能电视直播App的恶意监控

首先我们要指出中国广电总局推出的一个政策性文件是恶意监控的始作俑者,这个广电总局的政策性文件禁止智能电视和电视盒子安装直播软件。应该说这个政策性文件是为了保护特殊利益集团,阻挠技术进步和发展的。 有那么一些电视机和电视盒子的厂商和电信运…...

【JavaEE初阶】多线程初阶下部

文章目录 前言一、volatile关键字volatile 能保证内存可见性 二、wait 和 notify2.1 wait()方法2.2 notify()方法2.3 notifyAll()方法2.4 wait 和 sleep 的对比(面试题) 三、多线程案例单例模式 四、总结-保证线程安全的思路五、对比线程和进程总结 前言…...

macOS上进行Ant Design Pro实战教程(一)

由于一个AI项目的前端使用了umi,本教程根据阿里官网上的 《Ant Design 实战教程(beta 版)》来实操一下,我使用macOS操作系统,VS Code 开发环境。 一、开发环境 1、安装nodejs, npm, yarn 官网上建议使用cnpm&#xf…...

智能合约运行原理

点个关注吧!! 用一句话来总结,智能合约就像是一个自动售货机:你投入硬币(触发条件),选择商品(执行合约),然后机器就会自动给你商品(执行结果&…...

安卓动态添加View

在安卓应用中,有很多时候需要动态添加View。比如从后台获取商品列表,根据商品数量在页面渲染对应数量的条目,这时候就需要动态添加View。 1.动态添加View的方法 动态添加View有两种方法: 由代码生成子View:这种方式…...

前端预览pdf文件流

需求 后端接口返回pdf文件流,实现新窗口预览pdf。 解决方案 把后端返回的pdf文件流转为blob路径,利用浏览器直接预览。 具体实现步骤 1、引入axios import axios from axios;2、创建预览方法(具体使用时将axios的请求路径替换为你的后端…...

【测试工具JMeter篇】JMeter性能测试入门级教程(一)出炉,测试君请各位收藏了!!!

一、前言 Apache JMeter是纯Java的开源软件,最初由Apache软件基金会的Stefano Mazzocchi开发,旨在加载测试功能行为和测量性能。可以使用JMeter进行性能测试,即针对重负载、多用户和并发流量测试Web应用程序。 我们选择JMeter原因 是否测试过…...

【zookeeper03】消息队列与微服务之zookeeper集群部署

ZooKeeper 集群部署 1.ZooKeeper 集群介绍 ZooKeeper集群用于解决单点和单机性能及数据高可用等问题。 集群结构 Zookeeper集群基于Master/Slave的模型 处于主要地位负责处理写操作)的主机称为Leader节点,处于次要地位主要负责处理读操作的主机称为 follower 节点…...

从 Llama 1 到 3.1:Llama 模型架构演进详解

编者按: 面对 Llama 模型家族的持续更新,您是否想要了解它们之间的关键区别和实际性能表现?本文将探讨 Llama 系列模型的架构演变,梳理了 Llama 模型从 1.0 到 3.1 的完整演进历程,深入剖析了每个版本的技术创新&#…...

UE5肉鸽游戏教程学习

学习地址推荐:UE5肉鸽项目实战教程_哔哩哔哩_bilibili...

Vue3 - 详细实现虚拟列表前端虚拟滚动列表解决方案,vue3长列表优化之虚拟列表,解决列表动态高度不固定高度及图片视频图文异步请求加载问题,虚拟列表DOM大量数据同时加载渲染卡顿太慢及下滑列表闪烁

前言 Vue2 版本,请访问 这篇文章 在 vue3 项目开发中,详解实现虚拟列表高度不固定(不定高)且复杂含有图片视频等复杂虚拟列表教程,决列表每项高度不确定及img图像或视频的加载方案,利用缓冲区技术解决用户浏览时渲染不及时列表闪烁白屏/列表加载闪屏,解vue3实现虚拟列表优…...

英语知识网站开发:Spring Boot框架技巧

摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了英语知识应用网站的开发全过程。通过分析英语知识应用网站管理的不足,创建了一个计算机管理英语知识应用网站的方案。文章介绍了英语知识应用网站的系…...

基于lvgl+ST7735制作一款esp8285的控制面板程序

要在ESP8285上使用LVGL和ST7735创建一个控制面板程序,你需要遵循以下步骤。这个过程包括设置开发环境,连接硬件,编写代码,以及调校和优化。 所需硬件 ESP8285 开发板:像NodeMCU之类的开发板。ST7735 显示屏:通常是1.8英寸或2.0英寸的SPI接口显示屏。电源和连接线:用于连…...

MySQL 索引详解

在数据库的世界中,索引就像是一本巨大书籍的目录,它能够极大地提高数据检索的效率。在 MySQL 中,索引的合理使用对于数据库的性能至关重要。本文将深入探讨 MySQL 索引的各个方面。 一、索引的概念与作用 1. 什么是索引? 索引是一…...

区块链学习笔记(1)--区块、链和共识 区块链技术入门

常见的hash算法: 文件防篡改:MD5比特币挖矿:SHA256证明数据片段:Merkle root文本去重:SimHash 区块 区块(block)由区块头(block header)和交易列表(transac…...

【Android+多线程】IntentService 知识总结:应用场景 / 使用步骤 / 源码分析

定义 IntentService 是 Android中的一个封装类,继承自四大组件之一的Service 功能 处理异步请求 & 实现多线程 应用场景 线程任务 需 按顺序、在后台执行 最常见的场景:离线下载不符合多个数据同时请求的场景:所有的任务都在同一个T…...

Python Tornado框架教程:高性能Web框架的全面解析

Python Tornado框架教程:高性能Web框架的全面解析 引言 在现代Web开发中,选择合适的框架至关重要。Python的Tornado框架因其高性能和非阻塞I/O特性而备受青睐。它特别适合处理大量并发连接的应用,比如聊天应用、实时数据处理和WebSocket服务…...

我国政府门户网站建设现状/手机百度网盘登录入口

<?php /*** Filefifo.php 文件型FIFO队列*/ class Filefifo {/*** $_file_data, 数据文件的路径 */private $_file_data ;/*** $_file_idx, 索引文件的路径*/private $_file_idx ;/*** $_file_idx_bak, 索引备份文件的路径, 防止意外断电等导致索引文件破坏*/private $_f…...

信息化建设 公司网站/抖音自动推广引流app

之前在微信群内有朋友问我如何快速将多个Excel表格合并成一个Excel表格&#xff0c;当时没有讲解清楚&#xff0c;今天专门来告诉大家如何快速合并Excel表格到一个工作表中。在合并表格中&#xff0c;不外乎以下两种情况&#xff1a;将多个Excel表格文档合并成一个Excel表格将一…...

做外贸批发网站是哪个/微营销系统

2019独角兽企业重金招聘Python工程师标准>>> 出于效率和保持js库最小化的考虑&#xff0c;TWaver HTML5的Tree组件默认的交互方式比较单调&#xff0c;目前只有选中改变文字背景&#xff1b;但是这不代表TWaver功能不够强大&#xff0c;相反&#xff0c;TWaver预留了…...

开封网站制作/小吃培训2000元学6项

beanutils 是操作javabean 的属性 //较高级的操作 Student bean new Student(); BeanUtils.setProperty(bean, "age", "12"); //beanutils框架会自动对数据进行转换,这仅于8种基本数据类型 //高级的操作 Student bean new Student(); //注册日期…...

手机网页制作与网站建设/广州百度竞价开户

编译阶段&#xff1a;将java文件编译为class字节码文件 类加载 类加载&#xff1a;将class字节码加载进内存 1、加载(Loading) 将class类模型相关信息加载到方法区当中。 类加载器 BootStrapClassLoader 引导/启动类加载器 核心类库ExtensionClassLoader 扩展类加载器 特…...

做平面免费接单网站/品牌网络营销案例

map:数据的插入 在构造map容器后&#xff0c;我们就可以往里面插入数据了。这里讲三种插入数据的方法&#xff1a;第一种&#xff1a;用insert函数插入pair数据map<int, string> mapStudent;mapStudent.insert(pair<int, string>(1,“student_one”)); 第二种&…...