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…

【C++】C++ primer plus 第七、八章--函数

函数指针 使用typedef声明函数指针 typedef const double* (*p)(const double*, int);const double* func1(const double* a, int b){auto *c = new(double);*c = *a * b;return c; } // p则可以作为函数指针类型 p f = func1; 内联函数 使用关键字inline声明,在编译过程中…

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

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

详解SPWM与SVPWM的原理、算法以及两者的区别

详解SPWM与SVPWM的原理、算法以及两者的区别 1、SPWM与SVPWM 2、SPWM与SVPWM的原理 2.1 SPWM原理 2.2 SVPWM原理 3、SPWM与SVPWM的算法 3.1 SPWM算法 3.2 SVPWM 算法 4、SPWM和SVPWM的对比 5、总结 1、SPWM与SVPWM 所谓SPWM,就是在PWM的基础上改变了调制脉冲方式,…

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…

golang特性3

golang特性 通过通信共享内存 在 Go 中&#xff0c;通信共享内存是通过通道来实现的。Go 语言的设计哲学之一就是“不要通过共享内存来通信&#xff0c;而应通过通信来共享内存”。这意味着不鼓励直接在多个协程之间共享内存&#xff0c;而是通过通道进行数据交换&#xff0c…

C语言.指针(4)

指针&#xff08;4&#xff09; 1.回调函数是什么&#xff1f;2.qsprt使用举例2.1使用qsort函数排序整型数据2.2使用qsort函数排序结构体数据 3.qsort函数的模拟实现 1.回调函数是什么&#xff1f; 回调函数就是一个通过函数指针调用的函数 如果你把函数的指针&#xff08;地址…

Java集合体系面试题

1. Java中有哪些主要的集合接口&#xff1f; 答案&#xff1a;Java中主要的集合接口有Collection、List、Set、Queue和Map。 2. 请解释List和Set之间的主要区别。 答案&#xff1a;List和Set的主要区别在于元素的顺序和唯一性。List是有序的集合&#xff0c;允许存储重复的元…

PHP安装swoole拓展

一&#xff1a;下载swoole拓展 PHP的swoole拓展下载地址&#xff1a;https://pecl.php.net/package/swoole wget http://pecl.php.net/get/swoole-4.2.12.tgz二&#xff1a;安装swoole拓展 1&#xff1a;解压swoole拓展包 tar xzvf swoole-4.2.12.tgz cd swoole-4.2.122&am…

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常用设计模式介绍及代码示例

设计模式是在软件设计中发现、研究和应用的一种有效方法。设计模式并不直接转化成代码&#xff0c;而是提供了解决某一问题的框架。下面介绍一些常用的设计模式以及对应的Java代码示例&#xff1a; 1. 单例模式&#xff1a;确保某一个类只有一个实例&#xff0c;同时提供一个访…

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…

代码随想录第18天: 二叉树part05

力扣513 找树左下角的值 class Solution {public int findBottomLeftValue(TreeNode root) {Queue<TreeNode> que new LinkedList<>();que.offer(root);int res 0;while(!que.isEmpty()) {int size que.size();for(int i 0; i < size; i) {TreeNode tmp q…

Git(8)之分支间同步特定提交

Git(8)之分支间同步特定提交 Author&#xff1a;Once Day Date&#xff1a;2024年4月7日 漫漫长路有人对你微笑过嘛… 全系列文章可查看专栏: Git使用记录_Once_day的博客-CSDN博客 文章目录 Git(8)之分支间同步特定提交1. 分支间同步提交2. cherry-pick同步分支间的特定提交…

docker打包haproxy并代理web或mysql集群

1、需求&#xff1a; 使用haproxy代理两个服务&#xff08;web服务或者是mysql服务&#xff09; 2、编写Dockerfile 2.1、创建Dockerfile专用目录 mkdir /docker/images/haproxy -p && cd /docker/images/haproxy 2.2、下载软件包到Dockerfile专用目录 curl -O h…

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

前言 多线程大家肯定都不陌生&#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;作…