卷积定义
矩阵的掩码操作即对图像进行卷积。对图像卷积操作的意义为:邻近像素对(包括该像素自身)对新像素的影响;影响大小取决于卷积核对应位置值得大小。
例如:图像增强可以使用
\]
用代码实现
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 ...
随机推荐
-
Hawk 6. 编译和扩展开发
Hawk是开源项目,因此任何人都可以为其贡献代码.作者也非常欢迎使用者能够扩展出更有用的插件. 编译 编译需要Visual Stuido,版本建议使用2015, 2010及以上没有经过测试,但应该可以 ...
-
JAVA输入一个整数,求出其所有质因数
首先得求出能整除A的数,再判断I是否是质数!!! import java.util.*; public class aa { public static void main(String[] args ...
-
SVN安装与配置 SVN整合MyEclipse
SVN安装: 1.安装服务器 ######### 安装文件:SVN服务器############### # http://www.collab.net/downloads/subversion # C ...
-
Vijos P1063 迎春舞会之交谊舞 DP
题目链接:https://vijos.org/p/1063 题意:有n(n <= 100)行,每行有2*i-1个可显字符'#'与'-',组成一个倒三角形,问由'-'组成的最大三角形的'-'的个数 ...
-
sql 2000 ";无法执行查询,因为一些文件缺少或未注册";的
sql 2000 "无法执行查询,因为一些文件缺少或未注册"的解决办法 在SQL server 2000中打开表查看数据的时候,提示说“无法执行查询,因为一些文件缺少或未注册” 用 ...
-
Another attempt about LSI
Last week I was here Natural Language Processing in NZ. Someone asked a question, is there any exist ...
-
怎样成为一个游戏制作人——第五章:使用GGE图形库来写游戏
怎样成为一个游戏制作人--第五章:使用GGE图形库来写游戏 前言: 细致想了一下,来看博客的一般都是有自学能力的了.C++基础多少也会有一些了. 于是决定以下的章节.会教大家做一些小游戏. 来巩固自己 ...
-
Delphi 的绘图功能[10] - TFONT 类
Delphi 的绘图功能[10] - TFONT 类 ;DEFAULT_CHARSET = ;SYMBOL_CHARSET = ;SHIFTJIS_CHARSET = ;HAN ...
-
base 镜像 - 每天5分钟玩转容器技术(10)
上一节我们介绍了最小的 Docker 镜像,本节讨论 base 镜像. base 镜像有两层含义: 不依赖其他镜像,从 scratch 构建. 其他镜像可以之为基础进行扩展. 所以,能称作 base ...
-
ASP.NET Core 使用 URL Rewrite 中间件实现 HTTP 重定向到 HTTPS
在传统 ASP.NET 程序中,我们可以通过配置 IIS 的“URL 重写”功能实现将 HTTP 请求重定向为 HTTPS .但是该方法在 ASP.NET Core 应用中不再工作.在 ASP.NET ...