opencv 四 Mat的基本操作3(高通滤波、低通滤波、对比度调节)
图像滤波分为高通滤波和低通滤波,高通滤波用于求图形的边缘,低通滤波用于图像去噪、图像模糊化等。这里的频是指变化(相邻像素值的变化),高通滤波是指使变化大也就是图像的边缘)的通过(低通滤波是指使变化小(也就是图像中图形)的通过。高通滤波部分涉及到Sobel、Scharr、Laplacian、canny等方法; 低通滤波 部分涉及: 均值滤波,方框滤波、中值滤波、高斯滤波和双边滤波。对比度调节是通过修改图像中特定区域的像素值,使图像的对比度发生变化,本博文涉及的对比度调节方法有:数值加减运算、线性变化、非线性变化、直方图均衡化等手段。
一、高通滤波
高通滤波器有Sobel、Scharr、Laplacian、canny等,这些滤波器的特点是是图像中高频部分通过,过滤掉图像中的低频部分,其核心左右就是求图形的边缘(边缘检测算子都具有方向性);且这些滤波器的值之和为0。求边缘梯度时,为了避免噪声数据的影响,可以先使用一些低通滤波器去除噪声(如:高斯滤波)。进行滤波时,结果值可能大于255(超出CV_8U的范围),所以结果数据类型通常为16S,并需要通过convertScaleAbs函数将16S的范围压缩到CV_8U。
1.1 Sobel算子和Scharr算子
是一阶导数算子,对噪音适用性很强,在内部首先使用了高斯滤波对噪音进行过滤,之后再通过一阶导求得图像边缘。【若卷积核size设置为-1,则自动使用的是Scharr滤波算法】sobel算子的细节如下图所示,左图为x方向算子(求的是垂直方向的梯度),右图为y方向算子(求的是水平方向的梯度)
Sobel滤波算子的使用代码如下,其中需要注意的是Sobel可以求水平方向梯度和垂直方向梯度,所求的梯度值可能为负数,因此需要使用convertScaleAbs取绝对值。最终的梯度结果需要使用addWeighted函数进行加权求和。
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>using namespace std;
using namespace cv;int scale = 1;
int delta = 0;
int ddepth = CV_16S;int main()
{// 读入一张图片 Mat image = imread("C:\\Users\\aaa\\Pictures\\car1.png");//彩色图像转灰度图像cvtColor(image, image, COLOR_BGR2GRAY);imshow("原图", image);Mat grad_x, grad_y;Mat abs_grad_x, abs_grad_y;//求 X方向梯度,竖直边缘Sobel(image, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);//求 Y方向梯度,水平边缘Sobel(image, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);//将中间结果转换到 CV_8U:convertScaleAbs(grad_x, abs_grad_x);imshow("x", abs_grad_x);convertScaleAbs(grad_y, abs_grad_y);imshow("y", abs_grad_y);//将两个方向的梯度相加来求取近似 addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, image);imshow("sobel", image);waitKey(0);
}
代码运行效果如下所示:
虽然Sobel算子可以有效的提取图像边缘,但是对图像中较弱的边缘提取效果较差。因此为了能够有效的提取出较弱的边缘,需要将像素值间的差距增大,因此引入Scharr算子,其结构如下图所示。
Scharr算子是对Sobel算子差异性的增强,因此两者之间的在检测图像边缘的原理和使用方式上相同。Scharr算子的边缘检测滤波的尺寸为3×3,因此也有称其为Scharr滤波器。可以通过将滤波器中的权重系数放大来增大像素值间的差异。参考自【OpenCV 4开发详解】Scharr算子 - 知乎
1.2 Laplacian算子
拉普拉斯算子(Laplacian)可应用到图像边缘检测中。在OpenCV中当kernel大小为3*3时,支持两种kernel算子,分别如下图所示。Laplacian算子可以同时求水平方向和垂直方向的的梯度,具有无方向性的特点。Laplacian算子是一种二阶导数算子,对噪声比较敏感,因此常需要配合高斯滤波(去除噪声)一起使用。
调用代码如下所示:
Mat image = imread("C:\\Users\\aaa\\Pictures\\car1.png");//彩色图像转灰度图像cvtColor(image, image, COLOR_BGR2GRAY);imshow("原图", image);Mat grad;Laplacian(image, grad, CV_8U);convertScaleAbs(grad, grad);imshow("Laplacian", grad);waitKey(0);
代码结果如下所示
1.3 cany算子
cany算子分四步实现:消除噪声=》计算幅值和方向=》非极大值抑制=》滞后阈值,其计算幅值和方向时使用了sobel算子计算x和y方向的梯度值。具体细节如下博客所示OpenCV之Canny边缘检测(C++实现)https://blog.csdn.net/xddwz/article/details/111585648
如上述的三种滤波器相比,cany的计算流程较为复杂,且运算量较大。其使用代码和运行结果如下所示。
// 读入一张图片 Mat image = imread("C:\\Users\\aaa\\Pictures\\car1.png");//彩色图像转灰度图像cvtColor(image, image, COLOR_BGR2GRAY);imshow("原图", image);Mat grad;
/*
void Canny( InputArray image, OutputArray edges,double threshold1, double threshold2,int apertureSize = 3, bool L2gradient = false )
*/Canny(image, grad, 150, 100, 3);imshow("grad", grad);waitKey(0);
二、低通滤波
OpenCV中常用的低通滤波有: 均值滤波,方框滤波、中值滤波、高斯滤波和双边滤波,主要用于去除图像中的噪声。
2.1 均值滤波和方框滤波
均值滤波 可以帮助消除图像尖锐噪声,实现图像平滑,模糊等功能。理想的均值滤波是用每个像素和它周围像素计算出来的平均值替换图像中每个像素。
均值滤波有平均均值滤波和加权均值滤波。分别如下所示:
左边是平均均值滤波 右边是加权均值滤波
方框滤波和均值滤波的原理是类似的,方框滤波在进行归一化后效果和相同卷积核大小的均值滤波的效果相同。在OpenCV中,方框滤波的核大小就是指方框的行数和列数,具体如下图所示:
调用代码如下所示:
#include <iostream>
#include <opencv2\opencv.hpp>using namespace cv;
using namespace std;int main()
{//---------------------------用于方框滤波的图像--------------------Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);resize(img, img, { 500,300 });//将CV_8U类型转换成CV_32F类型,避免计算后的数据过大Mat equalImg_32F;img.convertTo(equalImg_32F, CV_32F, 1.0 / 255);Mat resultNorm, result, equalImg_32FSqr;//--------------------------方框滤波boxFilter----------------------boxFilter(img, resultNorm, -1, Size(3, 3), Point(-1, -1), true); // 进行归一化,则为均值滤波boxFilter(img, result, -1, Size(3, 3), Point(-1, -1), false); // 不进行归一化//----------------------方框滤波sqrBoxFilter()---------------------//对每个像素数值的平方求和/求均值sqrBoxFilter(equalImg_32F, equalImg_32FSqr, -1, Size(3, 3), Point(-1, -1), true, BORDER_CONSTANT);//-------------------------显示处理结果----------------------------imshow("原始图像", img);imshow("归一化", resultNorm);imshow("不归一化", result);imshow("平方和求均值", equalImg_32FSqr);waitKey(0);return 0;
}
代码运行效果如下·所示
2.2 中值滤波
中值滤波在一定的条件下可以克服常见线性滤波器如方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息, 保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。以下内容参考自:Opencv之图像滤波:5.中值滤波(cv2.medianBlur)_Justth.的博客-CSDN博客_opencv 中值滤波之前介绍的均值滤波、方框滤波、高斯滤波,都是线性滤波方式。由于线性滤波的结果是所有像素值的线性组合,因此含有噪声的像素也会被考虑进去,噪声不会被消除,而是以更柔和的方式存在。这时使用非线性滤波效果可能会更好。中值滤波与前面介绍的滤波方式不同,不再采用加权求均值的方式计算滤波结果。它用邻域内所有像素值的中间值来替代当前像素点的像素值。5.1 原理介绍中值滤波会取当前像素点及其周围临近像素点(一共有奇数个像素点)的像素值,将这些像素值排序,然后将位于中间位置的像素值作为当前像素点的像素值。 对如下矩..https://blog.csdn.net/qq_49478668/article/details/123485382
中值滤波会取当前像素点及其周围临近像素点(一共有奇数个像素点)的像素值,将这些像素值排序,然后将位于中间位置的像素值作为当前像素点的像素值。 对如下矩阵:
将其邻域设置为3×3大小,对其3×3邻域内像素点的像素值进行排序(升序降序均可),按升序排序后得到序列值为:[66,78,90,91,93,94,95,97,101]。在该序列中,处于中心位置(也叫中心点或中值点)的值是“93”,因此用该值替换原来的像素值78,作为当前点的新像素值。中值滤波效果如下:
调用代码如下所示:
#include <iostream>
#include <opencv2\opencv.hpp>using namespace cv;
using namespace std;int main()
{Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);resize(img, img, { 500,300 });Mat grayResult;medianBlur(img, grayResult , 3);imshow("原始图像", img);imshow("中值滤波", grayResult);waitKey(0);return 0;
}
代码运行效果如下:
2.3 高斯滤波
高斯滤波用于图像平衡、图像模糊或图像去噪,其本身是一个加权滤波的实现形式,高斯滤波的算子是有高斯分布函数计算而来的(中间的最重要,外围的次之)【高斯分布有标准差和方差两个参数】。高斯滤波的算子如下所示,其为每一个位置分配了不同权重,中间的权重最大,边缘的次之,所有的权重之和为1。
使用高斯滤波的代码和效果如下所示:
Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);resize(img, img, { 500,300 });Mat out;GaussianBlur(img, out, cv::Size(5, 5), 3, 3);imshow("原始图像", img);imshow("out", out);waitKey(0);
2.4 双边滤波
双边滤波(Bilateral filter)是一种非线性的滤波方法,双边滤波器的好处是可以做边缘保存(edge preserving)。一般用高斯滤波去降噪,会较明显地模糊边缘,对于高频细节的保护效果并不明显,而使用双边滤波可以达到高斯滤波的降噪效果,且能很好的保留边缘(因为进行双边滤波器时比高斯滤波多了一个高斯方差sigma-d)。内容参考自:OpenCV学习笔记(七)中值、双边滤波 - 简书
使用双边滤波的代码和效果如下所示:
Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);resize(img, img, { 500,300 });Mat out;/*bilateralFilter( InputArray src, OutputArray dst, int d,double sigmaColor, double sigmaSpace,int borderType = BORDER_DEFAULT )*/bilateralFilter(img, out, 25, 25 * 2, 25 / 2);imshow("原始图像", img);imshow("out", out);waitKey(0);
三、对比度调节
对比度调节是通过修改图像中特定区域的像素值,使图像的对比度发生变化。对比度增强是使亮部更亮、暗部更暗;对比度增强减弱是指使亮部变暗、暗部变亮。具体的对比度调节方法有:数值加减运算(无法增强对比度,只能使图像整体变亮或变暗)、线性变化(将像素值进行线性函数变化,y=ax+b,a>1时增强对比度,a<1时削弱对比度)、非线性变化(对数变化、gramma变化、自定义变化函数)、直方图均衡化等手段。
3.1 数值加减运算
通过对mat加减法可以调节图像的亮度(无法调节对比度),当加法运算结果超过255时为255,减法运算结果小于0时为0。
测试代码如下
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>using namespace std;
using namespace cv;
int main()
{Mat srcImage;srcImage = imread("C:/Users/aaa/Pictures/b.jpg", 0);resize(srcImage, srcImage,{},0.5,0.5);imshow("img", srcImage);Mat img_bl,img_an;//img_an = srcImage - 50;//减=》变暗img_bl = srcImage + 50;//加=》变亮imshow("img-50", img_an);imshow("img+50", img_bl);waitKey(0);return 0;
}
代码执行效果如下所示
3.2 线性运算
通过y=ax+b的线性函数映射修改像素值,a>1即增强对比度,a<1即降低对比度
测试代码如下
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>using namespace std;
using namespace cv;
int main()
{Mat srcImage;srcImage = imread("C:/Users/aaa/Pictures/b.jpg", 0);resize(srcImage, srcImage,{},0.5,0.5);imshow("img", srcImage);Mat img_bl,img_an;//img_an = srcImage*0.8 + 10;//a<1=》变暗img_bl = srcImage*1.5 - 30;//a>1=》变亮imshow("img*0.6 + 10", img_an);imshow("img*1.2 - 30", img_bl);waitKey(0);return 0;
}
代码执行效果如下所示
3.3 非线性变换
opencv中常见的非线性变换为对数变换(类凸函数,在y=x函数图像上方)和伽马变换 (随gamma值变化可在y=x函数图像下方,也可在其上方),此外我们还可以自定义非线性函数实现图像亮度的调节。
进行对数变化、gamma 的代码如下所示。进行对数变化时需要注意的是,对数变化对应的值域是0~255,但是进行对数变化后输出的值域却超过了255,故需要使用normalize函数进行值域压缩到0~255。而对于flaot型的mat,opencv理解的范围为[0,1],既超过1的部分均为白色,故最后需要将CV_32F转换为CV_8U(或使用normalize函数进行值域压缩到[0,1])
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>using namespace std;
using namespace cv;int main()
{Mat srcImage;srcImage = imread("C:/Users/aaa/Pictures/b.jpg", 0);resize(srcImage, srcImage,{},0.5,0.5);imshow("img", srcImage);//log变化、对数变化,使图像变亮Mat img_log;srcImage.convertTo(srcImage, CV_32F);log(srcImage, img_log);//log变化后图像值会出现小数,log函数的输出范围超出0~255normalize(img_log, img_log, 0, 255, NORM_MINMAX);//将log函数的输出压缩到0~255内img_log.convertTo(img_log, CV_8U);//因为图像是CV_32F,且值域超出0~1//gamma变化Mat g2_05=gamma_mat(srcImage, 2, 0.5);Mat g1_13 = gamma_mat(srcImage, 2, 1.3);imshow("img_log", img_log);imshow("g2_05", g2_05);imshow("g1_13", g1_13);waitKey(0);return 0;
}
其中gamma_mat函数的实现如下,需要注意的是 gamma函数变化针对的是0,1之间的值域,所以要将mat(值域为0~255)的像素值进行归一化(也就是现将CV_8U转换为CV_64F,然后除以255)。其运算结果也不在0,1之间,故需要进行也归一化(或者归255化)。
Mat gamma_mat(Mat src,float c, float gamma) {//伽马变换Mat gamma_image; //归一化图像src.convertTo(src, CV_64F);src = src / 255;int height = src.rows;int width = src.cols;gamma_image.create(src.size(), CV_64F);for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){gamma_image.at<double>(i, j) = c*pow(src.at<double>(i, j), gamma);};};//方式一 归一化normalize(gamma_image, gamma_image, 0, 1, NORM_MINMAX);//方式二 归255 转CV_8U//normalize(gamma_image, gamma_image, 0, 255, NORM_MINMAX);//gamma_image.convertTo(gamma_image, CV_8U);//方式三 归255 转CV_8U//gamma_image.convertTo(gamma_image, CV_8U, 255, 0);return gamma_image;
}
3.4 直方图均衡化
使用直方图均衡化可以增强图像对比度,其详细概念可以参考以下链接:
OpenCV 直方图均衡化_杨 戬的博客-CSDN博客_opencv直方图均衡化文章目录直方图均衡化介绍图像的直方图是什么?更形象解释什么是直方图均衡化?直方图均衡化是如何实现的?直方图均衡化的作用直方图均衡化步骤相关APIequalizeHist代码示例直方图均衡化介绍图像的直方图是什么?图像直方图,是指对整个图像像在灰度范围内的像素值(0~255)统计出现频率次数,据此生成的直方图,称为图像直方图-直方图。直方图反映了图像灰度的分布情况。是图像的统计学特征。简单来说:直方图是图像中像素强度分布的图形表达方式,它统计了每一个强度值所具有的像素个数。例如下面这张图片,左图为灰_1671465600https://blog.csdn.net/weixin_45525272/article/details/122663041
灰度图 直方图均衡化直接调用equalizeHist(in_mat,out_mat)即可,具体调用案例如下所示
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>using namespace std;
using namespace cv;int main()
{Mat srcImage;srcImage = imread("C:/Users/aaa/Pictures/a.jpg", 0);resize(srcImage, srcImage,{},0.5,0.5);imshow("原始图", srcImage);Mat new_img;equalizeHist(srcImage, new_img);imshow("经过直方图均衡化后的图", new_img);waitKey(0);return 0;
}
代码执行效果如下所示
彩色图 直方图均衡化不能直接对每一个通道进行均衡化,尤其是bgr图像。对于这种bgr图像需要先将颜色空间从BGR转换为HSV,然后将图像分割三个mat(分布对象H、S、V三个通道),对V通道的mat进行直方图均衡化即可。最后,要将H、S、V三个通道单通道mat合并为一个三通道的mat,然后将hsv颜色空间的mat转换为bgr的mat。具体操作如下所示
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>using namespace std;
using namespace cv;
Mat brgEqualizeHist(Mat bgr) {Mat hsvImg, dstImage;cvtColor(bgr, hsvImg, COLOR_BGR2HSV);//定义一个channels储存分离后的通道vector<Mat> channels;//H,S,V三个通道Mat h, s, v;//分离图像split(hsvImg, channels);h = channels.at(0);s = channels.at(1);v = channels.at(2);//对V通道就行直方图均衡化,使图像的亮度变得均衡equalizeHist(v, v);//将直方图均衡化的通道合并起来merge(channels, hsvImg);cvtColor(hsvImg, dstImage, COLOR_HSV2BGR);return dstImage;
}
int main()
{Mat srcImage;srcImage = imread("C:/Users/aaa/Pictures/a.jpg", 1);resize(srcImage, srcImage,{},0.5,0.5);imshow("原始图", srcImage);Mat new_bgr = brgEqualizeHist(srcImage);imshow("经过直方图均衡化后的图", new_bgr);waitKey(0);return 0;
}
代码执行效果如下所示
opencv 四 Mat的基本操作3(高通滤波、低通滤波、对比度调节)相关推荐
- OPENCV计算机视觉图像处理频域傅里叶 DFT 变换低通滤波逆变换IDFT
OpenCV计算机视觉图像频域傅里叶 DFT 变换低通滤波逆变换IDFT 实验室做图像的,经常用到这部分,为了检测屏幕,看过好多博客,试用过许多代码,这个算是我找到的比较好用的,也容易改. 傅里叶变换 ...
- 傅里叶变换 高通滤波 低通滤波
幅值谱:频率和幅值的关系.中心为频率最小点.因此幅值谱中心部分代表的是低频信息,即空间域的平缓的部分.越往外代表的是高频信息,空间域的边缘啊噪声等 频率:以正弦波为例,就是周期的倒数 幅值:周期内最大 ...
- c++ opencv数字图像处理:频率域滤波--低通滤波--巴特沃斯低通滤波
文章目录 前言 一.巴特沃斯低通滤波器(BLPF) 二.代码 三.说明 前言 数字图像处理c++ opencv(VS2019 opencv4.53)持续更新 一.巴特沃斯低通滤波器(BLPF) D2( ...
- 数字图像处理学习笔记5:频率域滤波1(傅里叶频谱图,低通滤波-平滑,高通滤波-锐化)
文章目录 前言 一.傅里叶变换:傅里叶频谱图 二.低通滤波 1.理想低通滤波 2.布特沃斯低通滤波 3.高斯低通滤波 4.小结 三.高通滤波 1.理想高通滤波 2.布特沃斯高通滤波 3.高斯高通滤波 ...
- 《OpenCv视觉之眼》Python图像处理七 :Opencv图像处理之高通滤波和低通滤波原理及构造
本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...
- opencv学习笔记22:傅里叶变换,高通滤波,低通滤波
傅里叶变换原理 任何连续的周期信号,都可以由一组适当的正弦曲线组合而成. 下列左上图由其他三图构成. 左图经过傅里叶变换,由时域图转换到频域图.相互可逆 相位:不是同时开始的一组余弦函数,在叠加时要体 ...
- 图像算法四:【图像增强--频率域】傅里叶变换、快速傅里叶变换、频域滤波、频域低通滤波、频域高通滤波
频率域滤波与空间域滤波殊途同归,空间域图像增强与频率域图像增强是两种截然不同的技术,实际上在相当程度上说它们是在不同的领域做相同的事情,只是有些滤波更适合在空间域完成,而有些则更适合在频率域中完成. ...
- OpenCV 高通滤波、低通滤波
高通滤波 低频.高频 频域滤波 代码示例 import cv2 import numpy as np import matplotlib.pyplot as plt#1.导入图片并进行傅里叶变换 im ...
- 【数字图像处理2.1 】频率域中的 高通滤波 和 低通滤波 Python+Opencv+Numpy
文章目录 前言 1.实验目的 2.频率域中高通.低通的效果图 3.代码 4.空间域滤波 与 频率域滤波比较 (1).回顾空间滤波 (2).相同点: (3).不同点: (4).二者关系: 前言 1.图像 ...
最新文章
- 《人工智能与工业融合发展研究报告》: AI入局推动工业产业6大趋势变化(附PPT)...
- .Net转Java自学之路—基础巩固篇十八(正则)
- Stage4--Python面向对象
- Android实现ListView圆角效果
- 利用OpenCV的findContours作轮廓检测
- shell逻辑运算符优先级_ios从入门到放弃之C基础巩固运算符
- 移动web开发框架之我见
- 教你怎样做个有“钱”途的測试project师
- bootstrap 按钮样式单选效果_【20201117】Bootstrap前端框架学习笔记
- 性价比不高却出到8?华为存在感最低的一个系列再发新机
- JavaScript事件委托的技术原理
- 怎样确定远程计算机ip地址,如何获取远程计算机的IP地址
- 1.Spring Boot使用Apache Curator实现服务的注册和发现「第四章 ZooKeeper Curator应用场景实战」「架构之路ZooKeeper理论和实战」
- 济南电子机械工程学校计算机专业班主任,济南电子机械工程学校
- Pinia——Vue 的存储库
- 三八女神节礼物排行,2022年三八节送女人什么礼物好?
- VirtualBox Guest Additions
- 嵌入式开发什么时候需要用RTOS?
- 不越狱安装iPa的原理
- SQL Server数据库安全规划全攻略(转)