OpenCV4.9处理平滑图像

返回:OpenCV系列文章目录(持续更新中......)

上一篇:使用OpenCV4.9的随机生成器和文本

下一篇:OpenCV系列文章目录(持续更新中......)

目标

在本教程中,您将学习如何使用 OpenCV 函数将不同的线性滤波器应用于平滑图像,例如:

  • blur()
  • GaussianBlur()
  • medianBlur()
  • bilateralFilter()

相关理论

注意

下面的解释属于 Richard Szeliski 的《计算机视觉:算法和应用》一书和 LearningOpenCV

  • 平滑,也称为模糊,是一种简单且常用的图像处理操作。
  • 平滑的原因有很多。在本教程中,我们将重点介绍平滑处理以减少噪声(其他用途将在以下教程中看到)。
  • 它有助于将滤镜可视化为在图像上滑动的系数窗口。

  • 过滤器有很多种,这里我们提一下最常用的:

归一化盒过滤器

  • 这个过滤器是最简单的!每个输出像素都是其内核邻居的平均(所有像素的权重相等)
  • 内核如下:

高斯滤波器

  • 可能是最有用的过滤器(虽然不是最快的)。高斯滤波是通过用高斯核对输入数组中的每个点进行卷积,然后将它们相加以生成输出数组来完成的。
  • 为了让图片更清晰,还记得一维高斯核的样子吗?

假设图像是 1D 的,您可以注意到位于中间的像素将具有最大的权重。其相邻像素的权重随着它们与中心像素之间的空间距离的增加而减小。

注意

请记住,二维高斯可以表示为:

中值滤波器

中值滤波器贯穿信号的每个元素(在本例中为图像),并将每个像素替换为其相邻像素的中位数(位于评估像素周围的方形邻域中)。

双边过滤器

  • 到目前为止,我们已经解释了一些过滤器,其主要目标是平滑输入图像。然而,有时滤波器不仅可以溶解噪声,还可以消除边缘。为了避免这种情况(至少在一定程度上),我们可以使用双边过滤器。
  • 与高斯滤波器类似,双边滤波器也会考虑相邻像素,并为每个像素分配权重。这些权重有两个组成部分,第一个分量与高斯滤波器使用的权重相同。第二个组件考虑了相邻像素和评估像素之间的强度差异。
  • 有关更详细的说明,您可以查看此链接

代码:

  • 这个程序是做什么的?
    • 加载图像
    • 应用 4 种不同类型的滤镜(在理论中解释)并按顺序显示滤波后的图像
  • 可下载代码: 点击这里
  • 代码一览:

C++: 

 
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"using namespace std;
using namespace cv;int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;Mat src; Mat dst;
char window_name[] = "Smoothing Demo";int display_caption( const char* caption );
int display_dst( int delay );int main( int argc, char ** argv )
{namedWindow( window_name, WINDOW_AUTOSIZE );const char* filename = argc >=2 ? argv[1] : "lena.jpg";src = imread( samples::findFile( filename ), IMREAD_COLOR );if (src.empty()){printf(" Error opening image\n");printf(" Usage:\n %s [image_name-- default lena.jpg] \n", argv[0]);return EXIT_FAILURE;}if( display_caption( "Original Image" ) != 0 ){return 0;}dst = src.clone();if( display_dst( DELAY_CAPTION ) != 0 ){return 0;}if( display_caption( "Homogeneous Blur" ) != 0 ){return 0;}for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){blur( src, dst, Size( i, i ), Point(-1,-1) );if( display_dst( DELAY_BLUR ) != 0 ){return 0;}}if( display_caption( "Gaussian Blur" ) != 0 ){return 0;}for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){GaussianBlur( src, dst, Size( i, i ), 0, 0 );if( display_dst( DELAY_BLUR ) != 0 ){return 0;}}if( display_caption( "Median Blur" ) != 0 ){return 0;}for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){medianBlur ( src, dst, i );if( display_dst( DELAY_BLUR ) != 0 ){return 0;}}if( display_caption( "Bilateral Blur" ) != 0 ){return 0;}for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){bilateralFilter ( src, dst, i, i*2, i/2 );if( display_dst( DELAY_BLUR ) != 0 ){return 0;}}display_caption( "Done!" );return 0;
}int display_caption( const char* caption )
{dst = Mat::zeros( src.size(), src.type() );putText( dst, caption,Point( src.cols/4, src.rows/2),FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );return display_dst(DELAY_CAPTION);
}int display_dst( int delay )
{imshow( window_name, dst );int c = waitKey ( delay );if( c >= 0 ) { return -1; }return 0;
}

Java:

import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;class SmoothingRun {int DELAY_CAPTION = 1500;int DELAY_BLUR = 100;int MAX_KERNEL_LENGTH = 31;Mat src = new Mat(), dst = new Mat();String windowName = "Filter Demo 1";public void run(String[] args) {String filename = ((args.length > 0) ? args[0] : "../data/lena.jpg");src = Imgcodecs.imread(filename, Imgcodecs.IMREAD_COLOR);if( src.empty() ) {System.out.println("Error opening image");System.out.println("Usage: ./Smoothing [image_name -- default ../data/lena.jpg] \n");System.exit(-1);}if( displayCaption( "Original Image" ) != 0 ) { System.exit(0); }dst = src.clone();if( displayDst( DELAY_CAPTION ) != 0 ) { System.exit(0); }if( displayCaption( "Homogeneous Blur" ) != 0 ) { System.exit(0); }for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.blur(src, dst, new Size(i, i), new Point(-1, -1));displayDst(DELAY_BLUR);}if( displayCaption( "Gaussian Blur" ) != 0 ) { System.exit(0); }for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.GaussianBlur(src, dst, new Size(i, i), 0, 0);displayDst(DELAY_BLUR);}if( displayCaption( "Median Blur" ) != 0 ) { System.exit(0); }for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.medianBlur(src, dst, i);displayDst(DELAY_BLUR);}if( displayCaption( "Bilateral Blur" ) != 0 ) { System.exit(0); }for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.bilateralFilter(src, dst, i, i * 2, i / 2);displayDst(DELAY_BLUR);}displayCaption( "Done!" );System.exit(0);}int displayCaption(String caption) {dst = Mat.zeros(src.size(), src.type());Imgproc.putText(dst, caption,new Point(src.cols() / 4, src.rows() / 2),Imgproc.FONT_HERSHEY_COMPLEX, 1, new Scalar(255, 255, 255));return displayDst(DELAY_CAPTION);}int displayDst(int delay) {HighGui.imshow( windowName, dst );int c = HighGui.waitKey( delay );if (c >= 0) { return -1; }return 0;}
}public class Smoothing {public static void main(String[] args) {// Load the native library.System.loadLibrary(Core.NATIVE_LIBRARY_NAME);new SmoothingRun().run(args);}
}

Python:

 

import sys
import cv2 as cv
import numpy as np# Global VariablesDELAY_CAPTION = 1500
DELAY_BLUR = 100
MAX_KERNEL_LENGTH = 31src = None
dst = None
window_name = 'Smoothing Demo' def main(argv):cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE)# Load the source imageimageName = argv[0] if len(argv) > 0 else 'lena.jpg'global srcsrc = cv.imread(cv.samples.findFile(imageName))if src is None:print ('Error opening image')print ('Usage: smoothing.py [image_name -- default ../data/lena.jpg] \n')return -1if display_caption('Original Image') != 0:return 0global dstdst = np.copy(src)if display_dst(DELAY_CAPTION) != 0:return 0# Applying Homogeneous blurif display_caption('Homogeneous Blur') != 0:return 0 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.blur(src, (i, i))if display_dst(DELAY_BLUR) != 0:return 0 # Applying Gaussian blurif display_caption('Gaussian Blur') != 0:return 0 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.GaussianBlur(src, (i, i), 0)if display_dst(DELAY_BLUR) != 0:return 0 # Applying Median blurif display_caption('Median Blur') != 0:return 0 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.medianBlur(src, i)if display_dst(DELAY_BLUR) != 0:return 0 # Applying Bilateral Filterif display_caption('Bilateral Blur') != 0:return 0 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.bilateralFilter(src, i, i * 2, i / 2)if display_dst(DELAY_BLUR) != 0:return 0 # Donedisplay_caption('Done!')return 0 def display_caption(caption):global dstdst = np.zeros(src.shape, src.dtype)rows, cols, _ch = src.shapecv.putText(dst, caption,(int(cols / 4), int(rows / 2)),cv.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255))return display_dst(DELAY_CAPTION) def display_dst(delay):cv.imshow(window_name, dst)c = cv.waitKey(delay)if c >= 0 : return -1return 0 if __name__ == "__main__":main(sys.argv[1:])

解释

让我们检查一下仅涉及平滑过程的 OpenCV 函数,因为其余的现在已经知道了。

归一化块滤波器:

  • OpenCV 提供了函数 blur() 来使用此过滤器执行平滑处理。我们指定 4 个参数(更多详细信息,请查看参考):
    • src:源图片
    • dst:目标图像
    • Size( w, h ):定义要使用的内核的大小(宽度 w 像素和高度 h 像素)
    • Point(-1, -1):指示锚点(评估的像素)相对于邻域的位置。如果存在负值,则将内核的中心视为锚点。
    • C++:
 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.blur(src, (i, i))if display_dst(DELAY_BLUR) != 0:return 0

 Java:

 for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.blur(src, dst, new Size(i, i), new Point(-1, -1));displayDst(DELAY_BLUR);}

Python: 

 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.blur(src, (i, i))if display_dst(DELAY_BLUR) != 0:return 0

Gaussian Filter:

  • 它由函数 GaussianBlur() 执行: 这里我们使用 4 个参数(更多细节,请查看 OpenCV 参考):

C++:

 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){GaussianBlur( src, dst, Size( i, i ), 0, 0 );if( display_dst( DELAY_BLUR ) != 0 ){return 0;}}

Java:

 for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.blur(src, dst, new Size(i, i), new Point(-1, -1));displayDst(DELAY_BLUR);}

python:

 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.GaussianBlur(src, (i, i), 0)if display_dst(DELAY_BLUR) != 0:return 0

中值过滤器:

  • 此过滤器由 medianBlur()函数提供: 我们使用三个参数:
    • src:源图片
    • dst:目标镜像,必须与 src 类型相同
    • i:内核的大小(只有一个,因为我们使用方形窗口)。一定是奇怪的。

C++:

 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){medianBlur ( src, dst, i );if( display_dst( DELAY_BLUR ) != 0 ){return 0;}}

Java:

 for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.medianBlur(src, dst, i);displayDst(DELAY_BLUR);}

Python: 

 for i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.medianBlur(src, i)if display_dst(DELAY_BLUR) != 0:return 0

双边过滤器

  • 由 OpenCV 函数 bilateralFilter() 提供 我们使用 5 个参数:
    • src:源图片
    • dst:目标图像
    • d:每个像素邻域的直径。

C++:

 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){bilateralFilter ( src, dst, i, i*2, i/2 );if( display_dst( DELAY_BLUR ) != 0 ){return 0;}}

Java:

 for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {Imgproc.bilateralFilter(src, dst, i, i * 2, i / 2);displayDst(DELAY_BLUR);}

Python:

 # Remember, bilateral is a bit slow, so as value go higher, it takes long timefor i in range(1, MAX_KERNEL_LENGTH, 2):dst = cv.bilateralFilter(src, i, i * 2, i / 2)if display_dst(DELAY_BLUR) != 0:return 0

结果

  • 该代码打开一个图像(在本例中为 lena.jpg),并在解释的 4 个过滤器的影响下显示它。
  • 以下是使用 medianBlur 平滑处理的图像快照:


参考文献:

1、《Smoothing Images》--------Ana Huamán​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/798036.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

助力瓷砖生产智造,基于YOLOv5全系列参数【n/s/m/l/x】模型开发构建瓷砖生产制造场景下1280尺寸瓷砖表面瑕疵检测识别系统

砖生产环节一般经过原材料混合研磨、脱水、压胚、喷墨印花、淋釉、烧制、抛光&#xff0c;最后进行质量检测和包装。得益于产业自动化的发展&#xff0c;目前生产环节已基本实现无人化。而质量检测环节仍大量依赖人工完成。一般来说&#xff0c;一条产线需要配数名质检工&#…

【三十三】【算法分析与设计】回溯(1),46. 全排列,78. 子集,没有树结构,但是依旧模拟树结构,回溯,利用全局变量+递归函数模拟树结构

46. 全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1&#xff0c;2&#xff0c;3] 输出&#xff1a;[[1&#xff0c;2&#xff0c;3]&#xff0c;[1&#xff0c;3&a…

缺陷检测项目 | 使用OpenCV实现纺织品表面缺陷检测

项目应用场景 面向纺织品表面缺陷检测场景&#xff0c;使用 OpenCV 来实现&#xff0c;因此无需深度学习复杂的训练流程&#xff0c;实现起来会更加便捷。 项目效果&#xff1a; 项目细节 > 具体参见项目 README.md 项目采用 VisualStudio C# 开发&#xff0c;所以用 Visua…

AcWing---转圈游戏---快速幂

太久没写快速幂了... 这是一道数学题orz&#xff0c;能看出来的话答案就是 &#xff0c;但是很大&#xff0c;同时还要mod n&#xff0c;直接用快速幂即可。 快速幂模版&#xff1a; long long int power(long long int a,long long int b,long long int mod){long long int r…

pandas(day6 图表)

一. 计算效率 1. 测量代码运行时间 %%time %%timeit 单纯计算 代码块执行的时长 %%time _sum(np.arange(6)) CPU times: total: 0 ns Wall time: 1.66 ms用于多次运行代码块并计算平均执行时间 %%timeit _sum(np.arange(6))738 ns 10.7 ns per loop (mean std. dev. of 7…

java流式计算Stream

java流式计算Stream 流(Stream)到底是什么呢? 是数据渠道&#xff0c;用于操作数据源&#xff08;集合、数组等&#xff09;所生成的元素序列。 “集合讲的是数据&#xff0c;流讲的是计算! ” 特点&#xff1a; Stream自己不会存储元素。 Stream不会改变源对象。相反&#x…

金三银四面试题(十六):MySQL面试都问什么(1)

在开发岗位面试中&#xff0c;MySQL基本是必考环节。所以接下来我们就进入MySQL八股文环节&#xff0c;看看都有哪些高频考题。 MySQL 中有哪些不同的表格&#xff1f; 在MySQL中&#xff0c;可以创建多种不同类型的表格&#xff0c;其中一些常见的类型包括&#xff1a; InnoD…

性能优化-如何爽玩多线程来开发

前言 多线程大家肯定都不陌生&#xff0c;理论滚瓜烂熟&#xff0c;八股天花乱坠&#xff0c;但是大家有多少在代码中实践过呢&#xff1f;很多人在实际开发中可能就用用Async&#xff0c;new Thread()。线程池也很少有人会自己去建&#xff0c;默认的随便用用。在工作中大家对…

ThingsBoard通过MQTT发送属性数据

MQTT基础 客户端 MQTT连接 属性上传API 案例 MQTT基础 MQTT是一种轻量级的发布-订阅消息传递协议&#xff0c;它可能最适合各种物联网设备。 你可以在此处找到有关MQTT的更多信息&#xff0c;ThingsBoard服务器支持QoS级别0&#xff08;最多一次&#xff09;和QoS级别1&…

3D打印技术引领压铸模具制造新变革

随着工业4.0浪潮的席卷&#xff0c;3D打印技术以其独特优势&#xff0c;正逐渐成为新一轮工业革命中的璀璨明星。这一技术不仅为“中国制造”向“中国智造”的转型提供了强大动力&#xff0c;也为压铸模具这一铸造行业的重要分支带来了前所未有的变革。 压铸模具&#xff0c;作…

文心一言指令词宝典之咨询分析篇

作者&#xff1a;哈哥撩编程&#xff08;视频号、抖音、公众号同名&#xff09; 新星计划全栈领域优秀创作者博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 &#x1f3c6; 推荐专栏&#xff1a; &#x1f3c5;…

NAT网络地址转换原理解析

NAT&#xff08;Network Address Translation&#xff09;&#xff0c;即网络地址转换&#xff0c;是一种在1994年提出的地址转换技术。它的主要目的是在本地网络中使用私有地址&#xff0c;在连接互联网时转而使用全局IP地址。NAT实际上是为解决IPv4地址短缺而开发的技术。NAT…

以诚待人,用心做事,做到最好,追求更好

无数个日日夜夜&#xff0c;终于换来了这样一份努力的证明。 2023年&#xff0c;收获满满&#xff0c;前一阵子拿到了证书&#xff0c;忘记拍照了&#xff0c;今天抽空记录一下 收获&#xff01;又得到一份肯定&#xff0c;这份荣誉证书将伴随我一直为了进步而奋斗&#xff1a…

基于SSM的基于个人需求和地域特色的外卖推荐系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的基于个人需求和地域特色的外卖推荐系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

非关系型数据库(缓存数据库)redis的集群

目录 一.群集模式——Cluster 1.原理 2.作用 3.特点 4.工作机制 哈希槽 哈希槽的分配 哈希槽可按照集群主机数平均分配&#xff08;默认分配&#xff09; 根据主机的性能以及功能自定义分配 redis集群的分片 分片 如何找到给定key的分片 优势 二. 搭建Redis群集…

TAB标签美化 - SVG作为mask

今天觉得V3的标签不是很好看&#xff0c;忽然想起来之前看过Vue Admin Beautiful Pro的样式挺好的&#xff0c;顺手研究了一把。发现Vue Admin Beautiful是采用PNGmask css来解决的。于是乎打算把V3的标签页做点小美化&#xff0c;但是迁移过程发生些小插曲&#xff0c;在此记录…

【算法】动态规划练习(一)

目录 1137. 第 N 个泰波那契数 分析 代码 面试题 08.01. 三步问题 分析 代码 746. 使用最小花费爬楼梯 分析 代码 泰波那契序列 Tn 定义如下&#xff1a; T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2 给你整数 n&#xff0c;请返回第 n 个泰波…

计算机网络——34LANs

LANs MAC地址和ARP 32bit IP地址 网络层地址用于使数据到达目标IP子网&#xff1a;前n - 1跳从而到达子网中的目标节点&#xff1a;最后一跳 LAN&#xff08;MAC/物理/以太网&#xff09;地址&#xff1a; 用于使帧从一个网卡传递到与其物理连接的另一个网卡&#xff08;在同…

数位排序(Comparator<int[]>())

题目 import java.util.Arrays; import java.util.Comparator; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();int m sc.nextInt();int[][] a new int[n][2];for(int i0;i…

C语言进阶课程学习记录-第25课 - # 和 ## 操作符使用分析

C语言进阶课程学习记录-第25课 - # 和 ## 操作符使用分析 #运算符实验-#转化字符串预处理后代码 实验-#输出函数名预处理后的代码 ##运算符实验-##定义变量预处理后代码 实验-##定义结构体预处理后的代码 小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图…