现在的网站内容区域做多宽,班级网站空间建设取得效果,南城网站建设公司案例,微信开发网站设计卷积与滤波概念
离散卷积
丢两个骰子#xff0c;求点数加起来为 ttt 的概率是多少#xff1f; 两个骰子加起来为4的概率#xff1a; f(1)g(3)f(2)g(2)f(3)g(1)f(1)g(3) f(2)g(2) f(3)g(1)f(1)g(3)f(2)g(2)f(3)g(1) 写成卷积标准形式为#xff1a; (f∗g)(4)∑i13f(i)g(…卷积与滤波概念
离散卷积
丢两个骰子求点数加起来为 ttt 的概率是多少 两个骰子加起来为4的概率 f(1)g(3)f(2)g(2)f(3)g(1)f(1)g(3) f(2)g(2) f(3)g(1)f(1)g(3)f(2)g(2)f(3)g(1) 写成卷积标准形式为 (f∗g)(4)∑i13f(i)g(4−i)(f *g)(4) \sum_{i1}^3f(i)g(4-i) (f∗g)(4)i1∑3f(i)g(4−i) 进一步两个骰子加起来为 ttt 的概率就是二个骰子的概率密度函数的卷积 (f∗g)(t)∑i1t−1f(i)g(t−i)(f *g)(t) \sum_{i1}^{t-1}f(i)g(t-i) (f∗g)(t)i1∑t−1f(i)g(t−i) 与1维卷积类似图像(二维)卷积定义 (f∗g)(x,y)1NM∑i0N−1∑j0M−1f(i,j)g(x−i,y−j)(f *g)(x,y) \frac{1}{NM}\sum_{i0}^{N-1}\sum_{j0}^{M-1}f(i,j)g(x-i,y-j) (f∗g)(x,y)NM1i0∑N−1j0∑M−1f(i,j)g(x−i,y−j) ggg 称为滤波器
图像滤波如何计算 滤波器 g(x,y)g(x,y)g(x,y) 左右、上下反转得到 g(−x,−y)g(-x,-y)g(−x,−y)按照前述公式计算卷积(先乘后累加)
图像平滑滤波与去噪
图像滤波由卷积定义基本知识
4-领域与8-领域
图像平滑
平均滤波在一个小区域内(通常3*3)像素值平均 g(x,y)1M∑i,jf(i,j)g(x,y) \frac{1}{M}\sum_{i,j}f(i,j) g(x,y)M1i,j∑f(i,j) 其中MMM表示像素值个数滤波器采用4-领域时M5M 5M5滤波器采用8-领域时M9M 9M9如果不考虑中间像素M8M 8M8。加权平均滤波在一个小区域内像素值加权平均 g(x,y)∑i,jwijf(i,j)g(x,y) \sum_{i,j}w_{ij}f(i,j) g(x,y)i,j∑wijf(i,j) 其中wijw_{ij}wij表示所有像素值之和的倒数。高斯滤波器元素值分布根据位置呈现高斯函数的特点 116[121242121]\frac{1}{16} \left[ \begin{array}{ccc} 1 2 1\\\\ 2 4 2\\\\ 1 2 1\\\\ \end{array} \right] 161⎣⎢⎢⎢⎢⎢⎢⎡121242121⎦⎥⎥⎥⎥⎥⎥⎤双边滤波器元素值不仅与位置有关还和源图像在该位置的像素值有关。其是空域核和值域核的叠加通过双边滤波器可以在使图像平滑的同时比较好的保留边缘。中值滤波确定窗口及位置(含有奇数个像素)窗口内像素按灰度大小排序取中间值代替原窗口中心像素值。对椒盐噪声有效。
总结
平滑滤波包括平均滤波、高斯滤波、中值滤波等方法其中高斯滤波最为常用。平滑滤波具有去除噪声效果不同滤波方法具有对不同噪声的适应性。
数学形态学滤波
数学形态学基本操作——膨胀和腐蚀
A⨁BA\bigoplus BA⨁B表示集合 AAA 用结构元素 BBB 膨胀(dilate)定义为 A⨁B∪(A)b(b∈B)A\bigoplus B \cup(A)_b (b\in B) A⨁B∪(A)b(b∈B) 表示将 AAA 按照 BBB 中的所有元素进行平移将所有平移的结果取并集。 A⨁BA\bigoplus BA⨁B表示集合 AAA 用结构元素 BBB 腐蚀(erode)定义为 A⨀B∩(A)−b(b∈B)A\bigodot B \cap(A)_{-b} (b\in B) A⨀B∩(A)−b(b∈B) 表示将 AAA 按照 BBB 中的所有元素进行反方向平移将所有平移的结果取并集。
直观表现是腐蚀使黑色区域变大了膨胀使白色区域变大了。
图像形态学操作——开闭运算
膨胀和腐蚀并不互为逆运算二者级联使用可生成新的形态学操作开运算先腐蚀后膨胀岛屿分开了 (A⨀B)⨁B(A\bigodot B)\bigoplus B (A⨀B)⨁B闭运算先膨胀后腐蚀岛屿闭合了 (A⨁B)⨀B(A\bigoplus B)\bigodot B (A⨁B)⨀B先开后闭可有效去除噪声
数学形态学去噪方法
实战演练图像平滑滤波对比
OpenCV实现滤波及平滑去噪各函数
图像滤波
dst cv2.filter2D(src, ddepth, kernel [, dst[, anchor[, delta[, borderType]]]])
#dst目标图像其与原图像尺寸和通道数相同
#ddepth目标图像的所需深度包括CV_16S/CV_32F/CV_64F等
#kernel卷积核(或相当于相关核)单通道浮点矩阵如果要将不同的内核应用与不同的通道请使用拆分再单独处理各通道
#anchor内核的锚点指示内核中过滤点的相对位置锚应位于内核中默认值(-1, -1)表示锚位于内核中心。
#detal在将它们存储在dst中之前将可选值添加到已过滤的像素中。类似于偏置。
#borderType卷积填充方式包括BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT等。平均滤波
dst cv2.blur(src, ksize[, dst[,anchor[, borderType]]])
#ksize:滤波器大小如(5, 5)高斯平滑滤波
dst cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])中值滤波
dst cv2.medianBlur(src, ksize[, dst])双边滤波
dst cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])
#d:过滤期间使用的各像素领域的直径
#sigmaColor:色彩空间的sigma参数该参数较大时各像素领域内相距较远的颜色会被混合到一起从而造成更大范围的半相等颜色
#sigmaSpace色彩空间的sigma参数该参数较大时只要颜色相近越远的像素会相互影响python代码
import cv2 as cv
import numpy as npdef gauss_noise(image, mean 0, var 0.001):添加高斯噪声mean: 均值var: 方差image np.array(image/255, dtype float)noise np.random.normal(mean, var ** 0.5, image.shape)out image noiseif out.min() 0:low_clip -1.else:low_clip 0.out np.clip(out, low_clip, 1.0)out np.uint8(out*255)# cv.imshow(Gauss_noise, out)return outfilename C:/python/img/lena.jpg
img cv.imread(filename)
img gauss_noise(img) #原图像加入高斯噪声blur cv.blur(img, (5, 5)) #平均滤波
gauss cv.GaussianBlur(img, (5, 5), 0) #高斯滤波
median cv.medianBlur(img, 5) #中值滤波
bilateral cv.bilateralFilter(img, 5, 150, 150) #双边滤波cv.imshow(Image, img)
cv.imshow(Blurred, blur)
cv.imshow(Gauss, gauss)
cv.imshow(Median filtered, median)
cv.imshow(Bilateral filtered, bilateral)cv.waitKey()
cv.destroyAllWindows()c添加高斯噪声 #include opencv2/core/core.hpp
#include opencv2/highgui/highgui.hpp
#include iostream
#include cstdlib
#include limits
#include cmath
using namespace cv;
using namespace std;
double generateGaussianNoise(double mu, double sigma)
{//定义一个特别小的值const double epsilon numeric_limitsdouble::min();//返回目标数据类型能表示的最逼近1的正数和1的差的绝对值static double z; //局部变量这样可以在不同的文件中定义同名函数和同名变量而不用担心命名冲突double u1, u2;//构造随机变量do{u1 rand()*(1.0 / RAND_MAX);u2 rand()*(1.0 / RAND_MAX);} while (u1 epsilon);//构造高斯随机变量Xz sqrt(-2.0*log(u1))*sin(2 * CV_PI * u2);return z * sigma mu;
}
//为图像添加高斯噪声
Mat addGaussianNoise(Mat srcImage)
{Mat resultImage srcImage.clone(); //深拷贝,克隆int channels resultImage.channels(); //获取图像的通道int nRows resultImage.rows; //图像的行数int nCols resultImage.cols*channels; //图像的总列数//判断图像的连续性if (resultImage.isContinuous()) //判断矩阵是否连续若连续我们相当于只需要遍历一个一维数组 {nCols * nRows;nRows 1;}for (int i 0; i nRows; i){for (int j 0; j nCols; j){ //添加高斯噪声int val resultImage.ptruchar(i)[j] generateGaussianNoise(2, 0.8) * 32;if (val 0)val 0;if (val 255)val 255;resultImage.ptruchar(i)[j] (uchar)val;}}return resultImage;
}
int main()
{Mat srcImage imread(lena.jpg, 1);if (!srcImage.data)return -1;imshow(srcImage, srcImage);Mat resultImage addGaussianNoise(srcImage);imshow(resultImage, resultImage);waitKey(0);return 0;
}关于代码里出现的OpenCV isContinuous()函数
bool cv::Mat::isContinuous() const该方法用于报告矩阵是否连续。 如果矩阵元素在每行末尾连续存储而没有间隙则方法返回true。 否则它返回false。 显然对于1x1或1xN矩阵总是连续的。一般 用Mat :: create创建的矩阵总是连续的。 2. Mat 数据类型指针ptr 的使用 这里的 depth_.ptr(y)[x] 就是指向depth _ 的第y 行的第x个数据数据类型为无符号的短整型。 char 是有符号的 uchar(unsigned char) 是无符号的,8-bit无符号整形数据里面全是正数 。 两者都作为字符用的话是没有区别的但当整数用时有区别 char 整数范围为-128到127( 0x80__0x7F) 而unsigned char 整数范围为0到255( 0__0xFF ) 有时候想把整数数值限在255范围内也用unsigned char。 而本例中resultImage.ptruchar(i)[j]是指向resultImage第 i 行第 j 个元素限制数值位0-255的整数。
#include iostream
#include opencv2/core/core.hpp
#include opencv2/highgui/highgui.hpp
#include opencv2/imgproc/imgproc.hppusing namespace std;
using namespace cv;typedef struct _imgPair {Mat *src;Mat *dst;void * Param;char* winName;
}ImgPair;typedef struct _gaussianParam {int kernelSize;int sigma;
}GaussianParam;typedef struct _bilateralParam {int kernelSize;int sigmaColor;int sigmaSpace;
}BilateralParam;void on_gaussiankernelBar(int ksize, void *userdata)
{ImgPair* pImgPair (ImgPair*)userdata;GaussianParam *gPair (GaussianParam *)(pImgPair-Param); //-用于指向结构体的指针表示结构体内的元素gPair-kernelSize ksize;GaussianBlur(*(pImgPair-src), *(pImgPair-dst), Size(gPair-kernelSize / 2 * 2 1, gPair-kernelSize / 2 * 2 1), gPair-sigma, gPair-sigma);//Mat类型的对象不直接做函数参数而是用指向它的指针//gPair-kernelSize / 2 * 2 1可以确保卷积核尺寸为奇数这样可以随意拖动bar不用担心拖到偶数//sigma.Xsigma.Y分别为XY方向卷积核的方差其中sigma.Y默认设置为0imshow(pImgPair-winName, *(pImgPair-dst));
}void on_gaussianSigmaBar(int sigma, void *userdata)
{ImgPair* pImgPair (ImgPair*)userdata;GaussianParam *gPair (GaussianParam *)(pImgPair-Param);gPair-sigma double(sigma);GaussianBlur(*(pImgPair-src), *(pImgPair-dst), Size(gPair-kernelSize / 2 * 2 1, gPair-kernelSize / 2 * 2 1), gPair-sigma, gPair-sigma);//无论拖动ksize的条还是sigma的条都要重新运行GuassianBlur函数重新计算。imshow(pImgPair-winName, *(pImgPair-dst));
}void on_medianSigmaBar(int ksize, void *userdata)
{ImgPair* pImgPair (ImgPair*)userdata;medianBlur(*(pImgPair-src), *(pImgPair-dst), ksize / 2 * 2 1);//中值滤波只有三个参数imshow(pImgPair-winName, *(pImgPair-dst));}void on_bilateralDBar(int ksize, void *userdata)
{//拖动双边滤波ksize的barImgPair* pImgPair (ImgPair*)userdata;BilateralParam *param (BilateralParam *)(pImgPair-Param);bilateralFilter(*(pImgPair-src), *(pImgPair-dst), ksize / 2 * 2 1, param-sigmaColor, param-sigmaSpace);//灰度距离核和空间距离核的sigmaparam-kernelSize ksize;imshow(pImgPair-winName, *(pImgPair-dst));}void on_bilateralSigmaSpaceBar(int sigmaSpace, void *userdata)
{ImgPair* pImgPair (ImgPair*)userdata;BilateralParam *param (BilateralParam *)(pImgPair-Param);bilateralFilter(*(pImgPair-src), *(pImgPair-dst), param-kernelSize / 2 * 2 1, param-sigmaColor, sigmaSpace);param-sigmaSpace sigmaSpace;imshow(pImgPair-winName, *(pImgPair-dst));
}void on_bilateralSigmaColorBar(int sigmaColor, void *userdata)
{ImgPair* pImgPair (ImgPair*)userdata;BilateralParam *param (BilateralParam *)(pImgPair-Param);bilateralFilter(*(pImgPair-src), *(pImgPair-dst), param-kernelSize / 2 * 2 1, sigmaColor, param-sigmaSpace);param-sigmaColor sigmaColor;imshow(pImgPair-winName, *(pImgPair-dst));
}int main()
{Mat src imread(lena.jpg);namedWindow(src);imshow(src, src);/*-------GaussianBlur-----------*/Mat GaussianBlurImg;namedWindow(GaussianBlurImg);GaussianParam gaussianParam { 5, 1.0 };GaussianBlur(src, GaussianBlurImg, Size(5, 5), 1, 1);GaussianParam gparam { 5, 1.0 };ImgPair gaussianPair { src, GaussianBlurImg, gparam, GaussianBlurImg };imshow(GaussianBlurImg, GaussianBlurImg);createTrackbar(kernelsize, GaussianBlurImg, (gparam.kernelSize), 30, on_gaussiankernelBar, gaussianPair);createTrackbar(sigma, GaussianBlurImg, (gparam.sigma), 10, on_gaussianSigmaBar, gaussianPair);
//createTrackbar是Opencv中的API其可在显示图像的窗口中快速创建一个滑动控件
//形式参数一、trackbarname滑动空间的名称
//形式参数二、winname滑动空间用于依附的图像窗口的名称
//形式参数三、value初始化阈值
//形式参数四、count滑动控件的刻度范围
//形式参数五、TrackbarCallback是回调函数其定义如下/*-------medianBlur-----------*/Mat MedianBlurImg;int kernelSize 5; //初始化的kerbelSizeImgPair medianPair { src, MedianBlurImg, nullptr, MedianBlurImg };medianBlur(src, MedianBlurImg, 5);imshow(MedianBlurImg, MedianBlurImg);createTrackbar(kernelsize, MedianBlurImg, (kernelSize), 30, on_medianSigmaBar, medianPair);/*---Bilateral-----------------*/Mat BilateralFilterImg;bilateralFilter(src, BilateralFilterImg, 5, 2, 2);BilateralParam bparam { 5,1,1 };ImgPair bilateralPair { src, BilateralFilterImg, bparam, BilateralFilterImg };imshow(BilateralFilterImg, BilateralFilterImg);createTrackbar(kernelsize, BilateralFilterImg, (bparam.kernelSize), 30, on_bilateralDBar, bilateralPair);createTrackbar(sigmaspace, BilateralFilterImg, (bparam.sigmaSpace), 30, on_bilateralSigmaSpaceBar, bilateralPair);createTrackbar(sigmacolor, BilateralFilterImg, (bparam.sigmaColor), 30, on_bilateralSigmaColorBar, bilateralPair);waitKey(0);
}
补充一个关于介绍滑动条的小程序使用滑动条做调色板
#include opencv2/core/core.hpp
#include opencv2/highgui/highgui.hpp
#include opencv2/imgproc/imgproc.hppusing namespace cv;//参数1滑动条位置参数2传入的参数
void nothing(int pos, void *)
{
}int main()
{Mat img Mat::zeros(300, 512, CV_8UC3);namedWindow(image);//createTrackbar函数为窗口创建滑动条createTrackbar(B, image, 0, 255, nothing);createTrackbar(G, image, 0, 255, nothing);createTrackbar(R, image, 0, 255, nothing);createTrackbar(0:off\n1:on, image, 0, 1, nothing);while (1){imshow(image, img);if (waitKey(1) 27)break;//getTrackbarPos函数作用获取滑动条的位置的值int b getTrackbarPos(B, image);int g getTrackbarPos(G, image);int r getTrackbarPos(R, image);int s getTrackbarPos(0:off\n1:on, image);if (s 0)img Scalar(0, 0, 0);else//opencv中颜色按BGR排列numpy、matplotlib常用的第三方库RGB排列img Scalar(b, g, r); //修改Mat类对象颜色的方法}waitKey(0);
}