基于opencv3.4.7 编程环境win10+VS2017、ubuntu18.04+Codelite
概述
参考链接:https://blog.csdn.net/zhuyong006/article/details/85682980
参考链接:https://www.cnblogs.com/invisible2/p/9177018.html
参考链接:https://blog.csdn.net/godadream/article/details/81568844
参考链接:https://www.jianshu.com/p/73e6ccbd8f3f
参考链接:https://blog.csdn.net/jiandanjinxin/article/details/51281828
图像处理中,常用的滤波算法有均值滤波、中值滤波以及高斯滤波等。
GaussianBlur()
函数用高斯滤波器GaussianFilter
对图像进行平滑处理。
该函数将源图像与指定的高斯内核进行卷积,同时也支持in-place
滤波。
原理通过2维高斯滤波函数计算出中心点周围每个点的权重分布,经归一化处理得到最终权重,各点权重*各点灰度值总和为高斯模糊后的中心点灰度值,每个点依次计算,得到整副图像模糊值,边缘点处理方法(补零、自动补齐等等)
三种滤波器比较如下
滤波种类 | 基本原理 | 特点 |
---|---|---|
均值滤波 | 使用模板内所有像素的平均值代替模板中心像素灰度值 | 易受到噪声的干扰,不能完全消除噪声,只能相对减弱噪声 |
中值滤波 | 计算模板内所有像素中的中值,并用所计算出来的中值体改模板中心像素的灰度值 | 对噪声不是那么敏感,能够较好的消除椒盐噪声,但是容易导致图像的不连续性 |
高斯滤波 | 对图像邻域内像素进行平滑时,邻域内不同位置的像素被赋予不同的权值 | 对图像进行平滑的同时,同时能够更多的保留图像的总体灰度分布特征 |
均值滤波就是将卷积核和图像对应位置相乘的结果取平均值赋给中心锚点的过程
中值滤波就是卷积核锚点对应的像素值用周边的元素的排序的中间值替代的过程,能很好地保护边缘信息
高斯滤波就是将卷积核按照高斯分布变成一定的权重值,最后将权重值和像素值相乘结果的和来替代锚点像素值的过程,按照高斯滤波的意思,离锚点越远的地方权重分配越低(离正态分布中心点越远)
API说明
高斯moC++API
void cv::GaussianBlur(InputArray src,OutputArray dst,Size ksize,double sigmaX,double sigmaY,int borderType=BORDER_DEFAULT)
参数说明
参数名称 | 作用 |
---|---|
src | (原始图像:channels 不限,各通道单独处理;depth 应当是CV_8U ,CV_16U ,CV_16S ,CV_32F 或CV_64F ) |
dst | (目标图像:与原始图像size 和type 一致) |
ksize | (高斯核大小,ksize.width 和ksize.height 可以不同,但是都必须为正的奇数(或者为0,此时它们的值会自动由sigma 进行计算)) |
sigmaX | (高斯核在x 方向的标准差) |
sigmaY=0 | (高斯核在y 方向的标准差(sigmaY=0 时,其值自动由sigmaX 确定(sigmaY=sigmaX );sigmaY=sigmaX=0 时,它们的值将由ksize.width 和ksize.height 自动确定)) |
borderType=BORDER_DEFAULT | (像素外插策略,可参考https://docs.opencv.org/3.4.1/d2/de8/group__core__array.html#ga209f2f4869e304c82d07739337eae7c5) |
ksize 一般奇数*奇数保证有中心点处于这个矩阵中央,sigmaX,sigmaY在图像处理中一般相等,进一步控制高斯核范围内x,y方向的模糊程度
均值模糊 C++API
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )
参数详解如下:
- 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处理的,且可以处理任意通道数的图片,但需要注意,待处理的图片深度应该为CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
- 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。比如可以用Mat::Clone,以源图片为模板,来初始化得到如假包换的目标图。
- 第三个参数,Size类型(对Size类型稍后有讲解)的ksize,内核的大小。一般这样写Size( w,h )来表示内核的大小( 其中,w 为像素宽度, h为像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小
- 第四个参数,Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
- 第五个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它。
中值模糊
void medianBlur(InputArray src, OutputArray dst, int ksize)
- InputArray src: 输入图像,图像为1、3、4通道的图像,当模板尺寸为3或5时,图像深度只能为CV_8U、CV_16U、CV_32F中的一个,如而对于较大孔径尺寸的图片,图像深度只能是CV_8U。
- OutputArray dst: 输出图像,尺寸和类型与输入图像一致,可以使用Mat::Clone以原图像为模板来初始化输出图像dst
- int ksize: 滤波模板的尺寸大小,必须是大于1的奇数,如3、5、7……
边缘模糊
void cv::bilateralFilter(InputArray src,OutputArray dst,int d,double sigmaColor,double sigmaSpace,int borderType = BORDER_DEFAULT )
- InputArray src: 输入图像,可以是Mat类型,图像必须是8位或浮点型单通道、三通道的图像。
- OutputArray dst: 输出图像,和原图像有相同的尺寸和类型。
- int d: 表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数,则函数会从第五个参数sigmaSpace计算该值。
- double sigmaColor: 颜色空间过滤器的sigma值,这个参数的值月大,表明该像素邻域内有越宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
- double sigmaSpace: 坐标空间中滤波器的sigma值,如果该值较大,则意味着越远的像素将相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace无关,否则d正比于sigmaSpace. (这个参数可以理解为空间域核w_d的\sigma_d)
- int borderType=BORDER_DEFAULT: 用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT.
示例代码
图片模糊
#include <opencv2/opencv.hpp>
int main()
{
// 创建两个窗口,分别显示输入和输出的图像
cv::namedWindow("Example2-5_in", cv::WINDOW_AUTOSIZE);
cv::namedWindow("Example2-5_out", cv::WINDOW_AUTOSIZE);
// 读取图像,并用输入的窗口显示输入图像
cv::Mat img = cv::imread("C:\\Users\\Bello\\Desktop\\test.jpg", -1);
cv::imshow("Example2-5_in", img);
// 声明输出矩阵
cv::Mat out;
// 进行平滑操作,可以使用GaussianBlur()、blur()、medianBlur()或bilateralFilter()
// 此处共进行了两次模糊操作
cv::GaussianBlur(img, out, cv::Size(5, 5), 3, 3);
cv::GaussianBlur(out, out, cv::Size(5, 5), 3, 3);
// 在输出窗口显示输出图像
cv::imshow("Example2-5_out", out);
// 等待键盘事件
cv::waitKey(0);
// 关闭窗口并释放相关联的内存空间
cv::destroyAllWindows();
return 0;
}
视频模糊
按键s单帧播放模式,按键r正常播放模式,按键q退出播放模式
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#define Pic_Path "/home/image/Pictures/"
#define Pic_Name "demo.jpg"
#define Video_Path "/home/image/Videos/"
#define Video_Name "test.mp4"
using namespace std;
int g_slider_position = 0;
int g_run = 1,g_dontset=0;
cv::VideoCapture g_cap;
//滑动条滑动时 触发该函数 将视频的当前帧与进度条相对应
void onTrackbarSlide(int pos, void *)
{
//正常播放时没有意义 进度条调整时该函数用来定位视频播放位置 用来与进度条滑块位置保持一致
g_cap.set(cv::CAP_PROP_POS_FRAMES, pos);
if(!g_dontset)
g_run = 1;
g_dontset=0;
}
int main(int argc, char **argv)
{
string pic = string(Pic_Path) + string(Pic_Name);
cout << pic << endl;
//获取视频完整路径及名称
string video = string(Video_Path) + string(Video_Name);
cout << video << endl;
//创建窗口
cv::namedWindow("原视频", cv::WINDOW_AUTOSIZE);
cv::namedWindow("高斯模糊视频",cv::WINDOW_AUTOSIZE);
cv::namedWindow("均值模糊视频",cv::WINDOW_AUTOSIZE);
cv::namedWindow("中值模糊视频",cv::WINDOW_AUTOSIZE);
//导入视频
//导入视频
g_cap.open(video);
//获取视频总帧数 分辨率 宽 高
int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);
int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH);
int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT);
cout << "Video has " << frames << " frames of dimensions(" << tmpw << "," << tmph << ")." << endl;
//创建滑动条
//参数1 滑动条名称
//参数2 窗口名称
//参数3 存储当前滑动条帧数
//参数4 总数 这里表示总帧数
//参数5 滑动条移动时调用的回调函数
cv::createTrackbar("Position", "原视频", &g_slider_position, frames, onTrackbarSlide);
//定义图像结构
cv::Mat frame;
cv::Mat dealframe;
cv::Mat mediaframe;
cv::Mat bilframe;
for (;;)
{
//如果g_run参数不为0
if (g_run != 0)
{
//原视频图像显示
g_cap >> frame;
if (frame.empty())
break;
cv::imshow("原视频", frame);
//高斯模糊处理
//参数1 原图像
//参数2 输出图像
//参数3 高斯核
//参数4 sigmax 高斯核x方向的标准差
//参数5 sigmay 高斯核y方向的标准差
//参数6 这里没有写出是高斯处理时边缘点的处理措施 默认是
cv::GaussianBlur(frame,dealframe,cv::Size(9,9),3,3);
cv::imshow("高斯模糊视频",dealframe);
#if 0
//均值模糊处理
//参数1 输入图像
//参数2 输出图像
//参数3 模糊范围
//参数4 模糊基准点
//参数5 边缘点处理
cv::blur(frame,dealframe,cv::Size(9,9),cv::Point(-1,-1));
cv::imshow("均值模糊视频",dealframe);
//中值模糊处理
//参数1 输入图像
//参数2 输出图像
//参数3 卷积范围 奇数
cv::medianBlur(frame,mediaframe,5);
cv::imshow("中值模糊视频",mediaframe);
#endif
//边缘模糊处理
//参数1 输入图像
//参数2 输出图像
//参数3 卷积计算范围 如果为0 按照第五个参数进行计算
//参数4 颜色差值在这个范围内的点将被计算模糊 差值大于该值保留原值增强边缘
//参数5 第三个参数的值大于0则声明无效 否则按照该值计算卷积范围
cv::bilateralFilter(frame,bilframe,15,180,5);
cv::imshow("边缘模糊视频",bilframe);
//获取当前帧 用来同步进度条进度
int current_pos = (int)g_cap.get(cv::CAP_PROP_POS_FRAMES);
g_dontset = 1;
//视频播放帧数与进度条进度能够同步
cv::setTrackbarPos("Position", "原视频", current_pos);
g_run -= 1;
cout << g_slider_position <<endl;
}
//判断按键输入 修改播放模式
char c = (char)cv::waitKey(20);
if (c == 's')
{
g_run = 1;
cout << "Single step,run = " << g_run << endl;
}
if (c == 'r')
{
g_run = -1;
cout << "Run mode , run = " << g_run << endl;
}
if (c == 'q')
break;
}
return 0;
}