卷积定义

矩阵的掩码操作即对图像进行卷积。对图像卷积操作的意义为:邻近像素对(包括该像素自身)对新像素的影响;影响大小取决于卷积核对应位置值得大小。

例如:图像增强可以使用

\[I(i,j)=5*I(i,j)-[I(i-1,j) + I(i+1,j) + I(i, j-1) + I(i, j+1)]
\]

用代码实现

 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、非线性平滑滤波器:最大值滤波、中值滤波、最小值滤波。

线性平滑滤波

线性平滑滤波可以减小“尖锐”,减小噪声;因为图像边缘是有“尖锐”变换引起的,所以也就模糊了边缘。

\[ \frac{1}{9}\left[
\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 )

有时各个像素的重要性不同,可以使用:

\[ \frac{1}{16}\left[
\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)

高斯滤波:卷积核是按照高斯分布的

\[G(x,y)=Ae^{\frac{-(x-\mu_x)^2}{2\sigma_x^2}+\frac{-(x-\mu_y)^2}{2\sigma_y^2}}
\]

和均值像素差值大的像素,对结果贡献较小;离均值“近”的像素,对结果贡献较大。

函数为:

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)-图像掩码操作(卷积)--平滑处理的更多相关文章

  1. OpenCV(5)-图像掩码操作(卷积)-锐化

    锐化概念 图像平滑过程是去除噪声的过程.图像的主要能量在低频部分,而噪声主要集中在高频部分.图像的边缘信息主要也在高频部分,在平滑处理后,将会丢不部分边缘信息.因此需要使用锐化技术来增强边缘. 平滑处 ...

  2. opencv——图像掩码操作

    使用opencv通过掩码去扣取图像中感兴趣的区域 步骤: 1.读取一张图片 2.转换颜色格式为hsv 3.设置要扣取区域颜色的上下门限 4.从原始图像中获取感兴趣区域的掩码 5.使用掩码和原始图像做云 ...

  3. OpenCV中图像算术操作与逻辑操作

    OpenCV中图像算术操作与逻辑操作 在图像处理中有两类最重要的基础操作各自是图像点操作与块操作.简单点说图像点操作就是图像每一个像素点的相关逻辑与几何运算.块操作最常见就是基于卷积算子的各种操作.实 ...

  4. OpenCV学习笔记:矩阵的掩码操作

    矩阵的掩码操作很简单.其思想是:根据掩码矩阵(也称作核)重新计算图像中每个像素的值.掩码矩阵中的值表示近邻像素值(包括该像素自身的值)对新像素值有多大影响.从数学观点看,我们用自己设置的权值,对像素邻 ...

  5. Opencv中图像的遍历与像素操作

    Opencv中图像的遍历与像素操作 OpenCV中表示图像的数据结构是cv::Mat,Mat对象本质上是一个由数值组成的矩阵.矩阵的每一个元素代表一个像素,对于灰度图像,像素是由8位无符号数来表示(0 ...

  6. opencv图像阈值操作

    使用threshold方法和adaptivethreshold方法对图像进行阈值分割操作. 1.使用threshold方法,设置一个阈值,将大于阈值的值变换为最大值,小于阈值的值变换为0. #-*- ...

  7. 【图像处理】OpenCV+Python图像处理入门教程(七)图像形态学操作

    图像形态学主要从图像内提取分量信息,该分量信息通常对表达图像的特征具有重要意义.例如,在车牌号码识别中,能够使用形态学计算其重要特征信息,在进行识别时,只需对这些特征信息运算即可.图像形态学在目标视觉 ...

  8. OpenCV在矩阵上的卷积

    转载请注明出处!!!http://blog.csdn.net/zhonghuan1992 OpenCV在矩阵上的卷积 在openCV官网上说是戴面具,事实上就是又一次计算一下矩阵中的每个value,那 ...

  9. opencv 6 图像轮廓与图像分割修复 3 图像的矩,分水岭,图像修补

    图像的矩 矩的计算:moments()函数 计算轮廓面积:contourArea()函数 #include "opencv2/highgui/highgui.hpp" #inclu ...

随机推荐

  1. HW5.7

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  2. HDU5407.CRB and Candies(数论)

    官方题解: The problem is just to calculate g(N) = LCM(C(N,0),C(N,1),...,C(N,N)) Introducing function f(n ...

  3. 使用innobackupex备份mysql数据库

    1  因为使用perl脚本编写,安装前应先安装 yum install perl-Time-HiRes -y yum -y install perl-DBD-MySQL.x86_64 一起安装     ...

  4. tomcat热部署,更改java类不用重新加载context

    修改类后,tomcat热部署会重新加载整个项目的context,影响开发效率.网上查的大多数是将server的modules标签中Auto Reload项改为Disabled,但是没有效果. 使用以下 ...

  5. 算法 - 求和为n的连续正整数序列(C++)

    //************************************************************************************************** ...

  6. QTP下载链接

    QTP下载链接 QTP官网下载:http://www8.hp.com/us/en/software-solutions/software.html?compURI=1172957#.UNMOQ2_FW ...

  7. 关机相关(shutdown,reboot)

    慣用的關機指令: shutdown 由於Linux的關機是那麼重要的工作,因此除了你是在主機前面以tty7圖形介面來登入系統時, 不論用什麼身份都能夠關機之外,若你是使用遠端管理工具(如透過piett ...

  8. ARM GCC CodeSourcery 下载地址

    Sourcery G++ Lite 2011.03-42: https://sourcery.mentor.com/GNUToolchain/package8737/public/arm-none-e ...

  9. SecureCRT恢复默认字体

    1\要想永久的改变的就跟我来吧,选项--全局选项--常规--默认会话--编辑默认设置--外观--当前颜色方案--选择自己喜欢的方案就行啦,然后选择保存就OK啦方案二: 自从装了Win7之后,觉得sec ...

  10. linux 配置 Apache mysql php最新版

    第一部分:安装mysql 官方下载 mysql5.6.19 64位的rpm格式文件 0.rpm 四个mysql5.6.19 卸载默认的mysql yum -y remove mysql-libs-* ...