OpenCV(4)-图像掩码操作(卷积)--平滑处理
卷积定义
矩阵的掩码操作即对图像进行卷积。对图像卷积操作的意义为:邻近像素对(包括该像素自身)对新像素的影响;影响大小取决于卷积核对应位置值得大小。
例如:图像增强可以使用
\]
用代码实现
void Sharpen(const Mat& myImage, Mat& Result)
{
CV_Assert(myImage.depth() == CV_8U); // 仅接受uchar图像
Result.create(myImage.size(), myImage.type());
const int nChannels = myImage.channels();
for (int j = 1; j < myImage.rows - 1; ++j)//从第一行开始,而不是0;到rows-2行结束
{
const uchar* previous = myImage.ptr<uchar>(j - 1);//上一行
const uchar* current = myImage.ptr<uchar>(j);
const uchar* next = myImage.ptr<uchar>(j + 1);//下一行
uchar* output = Result.ptr<uchar>(j);
for (int i = nChannels; i < nChannels*(myImage.cols - 1); ++i)
{
*output++ = saturate_cast<uchar>(5 * current[i]
- current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]);
}
}
//边缘处理。边缘没有卷积,所以边缘赋值为原图像对应像素的值。
//先处理上和下
uchar* output_top = Result.ptr<uchar>(0);
const uchar* origin_top = myImage.ptr<uchar>(0);
uchar* output_bottom = Result.ptr<uchar>(myImage.rows - 1);
const uchar* origin_bottom = Result.ptr<uchar>(myImage.rows - 1);
for (int i = 0; i < nChannels * myImage.cols - 1; ++i){
*output_top++ = *origin_top++;
*output_bottom++ = *origin_bottom++;
}
//左和右 分别有nChannel
for (int i = 0; i < myImage.rows; ++i){
const uchar* origin_left = myImage.ptr<uchar>(i);
uchar* output_left = Result.ptr<uchar>(i);
const uchar* origin_right = origin_left + nChannels*(myImage.cols - 1);
uchar* output_right = output_left + nChannels*(myImage.cols - 1);
for (int j = 0; j < nChannels; ++j){
*output_left++ = *origin_left++;
*output_right++ = *origin_right++;
}
}
}
卷积在图像处理中应用很广泛,可以使用OpenCV自带函数
void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT )

滤波器
滤波器中,所有元素和相加后应该等于1。如果大于1,则图像会变亮,如果小于1,图像变暗。
平滑滤波器
平滑滤波器的作用是去除图像中一些不重要的细节,减小噪声。可以分为线性和非线性2大类:
1、线性平滑滤波器:均值波滤器
2、非线性平滑滤波器:最大值滤波、中值滤波、最小值滤波。
线性平滑滤波
线性平滑滤波可以减小“尖锐”,减小噪声;因为图像边缘是有“尖锐”变换引起的,所以也就模糊了边缘。
\begin{matrix}
1 & 1 & 1 \\
1 & 1 & 1 \\
1 & 1 & 1
\end{matrix}
\right] \tag{3}
\]
上面这个滤波器,各个像素的值贡献相同,是均值滤波,在OpenCV有对应函数。
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )
有时各个像素的重要性不同,可以使用:
\begin{matrix}
1 & 2 & 1 \\
2 & 4 & 2 \\
1 & 2 & 1
\end{matrix}
\right] \tag{3}
\]
上面的滤波器表面中间和其挨着的像素贡献大一些。
非线性滤波
线性滤波是对滤波器区域内各个像素点加权求和,结果和原图像滤波区域有一个线性关系。非线性滤波则不然;基于统计排序的非线性滤波分为:最大值滤波、中值滤波、最小值滤波。顾名思义,上述三种滤波器是分别取卷积核区域内最大像素点值、中值像素点值、最小像素点值。
中值滤波:
中值滤波是对卷积核区域内像素排序,取中位数,只有奇数才有中位数,所有卷积核只能为3、5、7……这样的奇数。中值滤波在去除噪声的同时,可以比较好的保留图像细节(尖锐等),能够有效去除脉冲噪声(椒盐噪声)。
void medianBlur(InputArray src, OutputArray dst, int ksize)
高斯滤波:卷积核是按照高斯分布的
\]
和均值像素差值大的像素,对结果贡献较小;离均值“近”的像素,对结果贡献较大。
函数为:
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
双边滤波:
前面提高的滤波都是知识考虑了图像的空间关系,即卷积核区域内的空域关系,没有考虑像素间的关系。因此在平滑时,会模糊整幅图像;双边滤波不仅考虑了图像的空域关系,还考虑了图像间像素值的差异关系。可以参考这里
OpenCV对应函数
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT )
实验代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void Sharpen(const Mat& myImage, Mat& Result)
{
CV_Assert(myImage.depth() == CV_8U); // 仅接受uchar图像
Result.create(myImage.size(), myImage.type());
const int nChannels = myImage.channels();
for (int j = 1; j < myImage.rows - 1; ++j)//从第一行开始,而不是0;到rows-2行结束
{
const uchar* previous = myImage.ptr<uchar>(j - 1);//上一行
const uchar* current = myImage.ptr<uchar>(j);
const uchar* next = myImage.ptr<uchar>(j + 1);//下一行
uchar* output = Result.ptr<uchar>(j);
for (int i = nChannels; i < nChannels*(myImage.cols - 1); ++i)
{
*output++ = saturate_cast<uchar>(5 * current[i]
- current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]);
}
}
//边缘处理。边缘没有卷积,所以边缘赋值为原图像对应像素的值。
//先处理上和下
uchar* output_top = Result.ptr<uchar>(0);
const uchar* origin_top = myImage.ptr<uchar>(0);
uchar* output_bottom = Result.ptr<uchar>(myImage.rows - 1);
const uchar* origin_bottom = Result.ptr<uchar>(myImage.rows - 1);
for (int i = 0; i < nChannels * myImage.cols - 1; ++i){
*output_top++ = *origin_top++;
*output_bottom++ = *origin_bottom++;
}
//左和右 分别有nChannel
for (int i = 0; i < myImage.rows; ++i){
const uchar* origin_left = myImage.ptr<uchar>(i);
uchar* output_left = Result.ptr<uchar>(i);
const uchar* origin_right = origin_left + nChannels*(myImage.cols - 1);
uchar* output_right = output_left + nChannels*(myImage.cols - 1);
for (int j = 0; j < nChannels; ++j){
*output_left++ = *origin_left++;
*output_right++ = *origin_right++;
}
}
}
int main(int argc, char* argv[]){
const char* path = "";
Mat img = imread(path);
if (img.empty())
{
cout << "error";
return -1;
}
imshow("原图像", img);
//均值滤波
Mat blur_mat;
blur(img, blur_mat, Size(3, 3));
imshow("均值滤波", blur_mat);
//线性非均值滤波
Mat kern = (Mat_<float>(3, 3) << 1, 2, 1,
2, 4, 2,
1, 2, 1) / 16;
Mat blur2_mat;
filter2D(img, blur2_mat, img.depth(), kern);
imshow("线性非均值滤波", blur2_mat);
//中值滤波
Mat memedian_mat;
medianBlur(img, memedian_mat, 3);
imshow("中值滤波", memedian_mat);
//高斯滤波
Mat Gaussian_mat;
GaussianBlur(img, Gaussian_mat, Size(3, 3), 0, 0);
imshow("高斯滤波", Gaussian_mat);
//双边滤波
Mat bilateral_mat;
bilateralFilter(img, bilateral_mat, 25, 25 * 2, 25 / 2);
imshow("双边滤波", bilateral_mat);
waitKey();
return 0;
}
OpenCV(4)-图像掩码操作(卷积)--平滑处理的更多相关文章
- OpenCV(5)-图像掩码操作(卷积)-锐化
锐化概念 图像平滑过程是去除噪声的过程.图像的主要能量在低频部分,而噪声主要集中在高频部分.图像的边缘信息主要也在高频部分,在平滑处理后,将会丢不部分边缘信息.因此需要使用锐化技术来增强边缘. 平滑处 ...
- opencv——图像掩码操作
使用opencv通过掩码去扣取图像中感兴趣的区域 步骤: 1.读取一张图片 2.转换颜色格式为hsv 3.设置要扣取区域颜色的上下门限 4.从原始图像中获取感兴趣区域的掩码 5.使用掩码和原始图像做云 ...
- OpenCV中图像算术操作与逻辑操作
OpenCV中图像算术操作与逻辑操作 在图像处理中有两类最重要的基础操作各自是图像点操作与块操作.简单点说图像点操作就是图像每一个像素点的相关逻辑与几何运算.块操作最常见就是基于卷积算子的各种操作.实 ...
- OpenCV学习笔记:矩阵的掩码操作
矩阵的掩码操作很简单.其思想是:根据掩码矩阵(也称作核)重新计算图像中每个像素的值.掩码矩阵中的值表示近邻像素值(包括该像素自身的值)对新像素值有多大影响.从数学观点看,我们用自己设置的权值,对像素邻 ...
- Opencv中图像的遍历与像素操作
Opencv中图像的遍历与像素操作 OpenCV中表示图像的数据结构是cv::Mat,Mat对象本质上是一个由数值组成的矩阵.矩阵的每一个元素代表一个像素,对于灰度图像,像素是由8位无符号数来表示(0 ...
- opencv图像阈值操作
使用threshold方法和adaptivethreshold方法对图像进行阈值分割操作. 1.使用threshold方法,设置一个阈值,将大于阈值的值变换为最大值,小于阈值的值变换为0. #-*- ...
- 【图像处理】OpenCV+Python图像处理入门教程(七)图像形态学操作
图像形态学主要从图像内提取分量信息,该分量信息通常对表达图像的特征具有重要意义.例如,在车牌号码识别中,能够使用形态学计算其重要特征信息,在进行识别时,只需对这些特征信息运算即可.图像形态学在目标视觉 ...
- OpenCV在矩阵上的卷积
转载请注明出处!!!http://blog.csdn.net/zhonghuan1992 OpenCV在矩阵上的卷积 在openCV官网上说是戴面具,事实上就是又一次计算一下矩阵中的每个value,那 ...
- opencv 6 图像轮廓与图像分割修复 3 图像的矩,分水岭,图像修补
图像的矩 矩的计算:moments()函数 计算轮廓面积:contourArea()函数 #include "opencv2/highgui/highgui.hpp" #inclu ...
随机推荐
- HDU2639Bone Collector II(01背包变形)
01背包,求第k大. 以前看k短路的时候看过代码以为懂了 = =结果还是跑去看了别人的代码才会.果然要自己写一遍才行啊 0.0难得1A.. 每次把可能的2k种求出来,求前k个.注意要不一样的k个数.. ...
- 数据绑定之DataFormatString
设定BoundField的DataFormatString,通常有以下几种 DataFormatString= "{0:C}" 货币,货币的格式取决于当前Thread中Cultur ...
- 读FCL源码系列之List<T>---让你知其所以然---内含疑问求大神指点
序言 在.NET开发中,List<T>是我们经常用到的类型.前段时间看到其他部门小伙伴讨论“两个List(10W个元素)集合求并集,list1.Where(p=>list2.Cont ...
- Webdriver:Unsupported Marionette protocol version 2, required 3
升级到firefox到47以上版本即可 坑人的Mozilla不能起个我们熟识的名字吗? 先是webdriver.gecko.driver后是Marionette protocol. 1.WebDr ...
- Objective-C-使用NSMutableURLRequest发送POST请求,使用NSJSONSerialization解析JSON字符串
NSString *reqData = @"Data="; NSData *postDatas = nil; NSString *urlPath = @"url" ...
- uedit富文本编辑器
问题: 1: An error occurred at line: 6 in the generated java fileOnly a type can be imported. com.baidu ...
- c++虚表的使用 通过虚表调用虚函数的演示代码
//演示一下c++如何找到虚表地址vptr以及如何通过虚表调用虚函数 //zhangpeng@myhexin.com 20130811 #include <iostream> using ...
- Android-ViewPagerIndicator
https://github.com/JakeWharton/Android-ViewPagerIndicator
- bind的例子
10.24 给定一个string,使用bind和check_size在一个int的vector中查找第一个大于string长度的值. #include<iostream> #include ...
- Referenced file contains errors (http://www.springframework.org/schema...错误--转载
Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-3.0.xsd). ...