【OpenCV教程】滤波和边缘检测的过程
2024/8/19 21:02:56
本文主要是介绍【OpenCV教程】滤波和边缘检测的过程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
@TOC
1.均值滤波
1.1 卷积核形状
Mat kernal=Mat::ones(Size(ksize,ksize),CV_64F)/(ksize*ksize);
1.2 API
CV_EXPORTS_W void blur( InputArray src, OutputArray dst, Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片 |
dst(destination) | 输出图片 |
ksize(kernal size) | 卷积核宽高,必须是正奇数 |
anchor | 滤波器中心像素位置,取(-1,-1)表示几何中心 |
borderType | 边界填充方式,默认为黑边 |
1.3 效果
Mat xuenai = imread("xuenai.jpg"); imshow("xuenai",xuenai); Mat xuenai_blur(xuenai.size(),xuenai.type()); blur(xuenai,xuenai_blur,Size(3,5)); imshow("xuenai_blur",xuenai_blur); waitKet();
2.高斯滤波
2.1 卷积核形状
二维高斯函数表述为:
G(x,y)=12πσ2e−(x−x0)2+(y−y0)22σ2 G(x,y)=\frac{1}{2 \pi \sigma^{2}}e^{- \frac{(x-x_{0})^{2}+(y-y_{0})^{2}}{2\sigma^{2}}} G(x,y)=2πσ21e−2σ2(x−x0)2+(y−y0)2
对应图形:
代码实现(不区分sigmaX与sigmaY)
void GetGaussianKernel(Mat kernal, const int ksize,const double sigma) { const double PI=4.0*atan(1.0); //圆周率π赋值 int center= ksize/2; double sum=0; for(int i=0;i<ksize;i++) { for(int j=0;j<ksize;j++) { kernal.ptr(i,j)=(1/(2*PI*sigma*sigma))*exp(-((i-center)*(i-center)+(j-center)*(j-center))/(2*sigma*sigma)); sum+=kernal.ptr(i,j); } } for(int i=0;i<ksize;i++) { for(int j=0;j<ksize;j++) { kernal.ptr(i,j)/=sum; } } return ; }
2.2 API
CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片 |
dst(destination) | 输出图片 |
ksize(kernal size) | 卷积核宽高。如果这个尺寸我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。 |
sigmaX | x方向上的标准差 |
sigmaY | y方向上的标准差。默认输入量为0,则将其设置为等于sigmaX,如果两个轴的标准差均为0,则根据输入的高斯滤波器尺寸计算标准偏差。 |
borderType | 边界填充方式,默认为黑边 |
2.3 效果
Mat xuenai = imread("xuenai.jpg"); imshow("xuenai",xuenai); Mat xuenai_Gauss(xuenai.size(),xuenai.type()); GaussianBlur(xuenai,xuenai_Gauss,Size(-1,-1),10); imshow("xuenai_Gauss",xuenai_Gauss); waitKet();
3.中值滤波
3.1 原理
取滤波器内的中值作为输出,可以很好的抑制椒盐噪声
3.2 API
CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片 |
dst(destination) | 输出图片 |
ksize(kernal size) | 卷积核边长,必须是正奇数 |
3.3 效果
Mat xuenai = imread("xuenai.jpg"); imshow("xuenai",xuenai); Mat xuenai_median(xuenai.size(),xuenai.type()); medianBlur(xuenai,xuenai_median,5); imshow("xuenai_median",xuenai_median); waitKet();
4.高斯双边滤波
4.1 原理
双边滤波器的好处是可以做边缘保存(edge preserving),一般用高斯滤波去降噪,会较明显地模糊边缘,对于高频细节的保护效果并不明显。双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。
4.2 API
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片 |
dst(destination) | 输出图片 |
d | 卷积核边长。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。 |
sigmaColor | 颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。 |
sigmaSpace | 坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,卷积核大小已被指定且与sigmaSpace无关。否则,d正比于sigmaSpace。 |
borderType | 边界填充方式,默认为黑边 |
4.3 效果
Mat xuenai = imread("xuenai.jpg"); imshow("xuenai",xuenai); Mat xuenai_bilateral(xuenai.size(),xuenai.type()); bilateralFilter(xuenai,xuenai_bilateral,-1,100,10); imshow("xuenai_bilateral",xuenai_bilateral); waitKet();
5.获取用来形态学操作的滤波器
CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1)); enum MorphShapes { MORPH_RECT = 0, //!< a rectangular structuring element: \f[E_{ij}=1\f] MORPH_CROSS = 1, //!< a cross-shaped structuring element: //!< \f[E_{ij} = \begin{cases} 1 & \texttt{if } {i=\texttt{anchor.y } {or } {j=\texttt{anchor.x}}} \\0 & \texttt{otherwise} \end{cases}\f] MORPH_ELLIPSE = 2 //!< an elliptic structuring element, that is, a filled ellipse inscribed //!< into the rectangle Rect(0, 0, esize.width, 0.esize.height) };
shape:滤波器形状
ksize(kernal size):滤波器大小
anchor:滤波器中心像素位置,取(-1,-1)表示几何中心
6.腐蚀和膨胀(对二值图)
6.1 原理
腐蚀:取滤波器内的最小值作为输出
膨胀:取滤波器内的最大值作为输出
6.2 腐蚀API
CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片,尽量是二值图 |
dst(destination) | 输出图片 |
kernal | 滤波器矩阵 |
anchor | 滤波器中心像素位置,取(-1,-1)表示几何中心 |
iterations | 执行erode函数的次数,默认执行一次 |
borderType | 边界填充方式,默认为黑边 |
borderValue | 填充边界的值 |
6.3 效果
Mat xuenai = imread("xuenai.jpg"); Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); Mat xuenai_threshold(xuenai.size(),xuenai.type()); threshold(xuenai_gray,xuenai_threshold,100,255,THRESH_BINARY); imshow("xuenai_threshold",xuenai_threshold); Mat kernal=getStructuringElement(MORPH_RECT,Size(3,3)); Mat xuenai_erode(xuenai.size(),xuenai.type()); erode(xuenai_threshold,xuenai_erode,kernal); imshow("xuenai_erode",xuenai_erode); waitKet();
6.4 膨胀API
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片,尽量是二值图 |
dst(destination) | 输出图片 |
kernal | 滤波器矩阵 |
anchor | 滤波器中心像素位置,取(-1,-1)表示几何中心 |
iterations | 执行erode函数的次数,默认执行一次 |
borderType | 边界填充方式,默认为黑边 |
borderValue | 填充边界的值 |
6.5 效果
Mat xuenai = imread("xuenai.jpg"); Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); Mat xuenai_threshold(xuenai.size(),xuenai.type()); threshold(xuenai_gray,xuenai_threshold,100,255,THRESH_BINARY); imshow("xuenai_threshold",xuenai_threshold); Mat kernal=getStructuringElement(MORPH_RECT,Size(3,3)); Mat xuenai_dilate(xuenai.size(),xuenai.type()); dilate(xuenai_threshold,xuenai_dilate,kernal); imshow("xuenai_dilate",xuenai_dilate); waitKet();
7.形态学操作(对二值图)
7.1 API
CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片,尽量是二值图 |
dst(destination) | 输出图片 |
op(option) | 变换类型 |
kernal | 滤波器矩阵 |
anchor | 滤波器中心像素位置,取(-1,-1)表示几何中心 |
iterations | 执行erode函数的次数,默认执行一次 |
borderType | 边界填充方式,默认为黑边 |
borderValue | 填充边界的值 |
7.2 变换类型
enum MorphTypes{ MORPH_ERODE = 0, //腐蚀 MORPH_DILATE = 1, //膨胀 MORPH_OPEN = 2, //开 MORPH_CLOSE = 3, //闭 MORPH_GRADIENT = 4, //形态学梯度 MORPH_TOPHAT = 5, //顶帽 MORPH_BLACKHAT = 6, //黑帽 MORPH_HITMISS = 7 //击中击不中变换 };
7.3 开
原理
对输入图片先进行腐蚀,然后进行膨胀。可以用来屏蔽与滤波器大小相当的亮部。
效果
Mat xuenai = imread("xuenai.jpg"); Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); Mat xuenai_threshold(xuenai.size(),xuenai.type()); threshold(xuenai_gray,xuenai_threshold,100,255,THRESH_BINARY); imshow("xuenai_threshold",xuenai_threshold); Mat kernal=getStructuringElement(MORPH_RECT,Size(3,3)); Mat xuenai_morphology(xuenai.size(),xuenai.type()); morphologyEx(xuenai_threshold,xuenai_morphology,MORPH_OPEN,kernal); imshow("xuenai_morphology",xuenai_morphology); waitKet();
7.4 闭
原理
对输入图片先进行膨胀,然后进行腐蚀。可以用来屏蔽与滤波器大小相当的暗部。
效果
Mat xuenai = imread("xuenai.jpg"); Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); Mat xuenai_threshold(xuenai.size(),xuenai.type()); threshold(xuenai_gray,xuenai_threshold,100,255,THRESH_BINARY); imshow("xuenai_threshold",xuenai_threshold); Mat kernal=getStructuringElement(MORPH_RECT,Size(3,3)); Mat xuenai_morphology(xuenai.size(),xuenai.type()); morphologyEx(xuenai_threshold,xuenai_morphology,MORPH_CLOSE,kernal); imshow("xuenai_morphology",xuenai_morphology); waitKet();
7.5 顶帽
原理
对输入图片先进行开操作,然后原图-开操作图。可以用来提取与滤波器大小相当的亮部。
效果
Mat xuenai = imread("xuenai.jpg"); Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); Mat xuenai_threshold(xuenai.size(),xuenai.type()); threshold(xuenai_gray,xuenai_threshold,100,255,THRESH_BINARY); imshow("xuenai_threshold",xuenai_threshold); Mat kernal=getStructuringElement(MORPH_RECT,Size(3,3)); Mat xuenai_morphology(xuenai.size(),xuenai.type()); morphologyEx(xuenai_threshold,xuenai_morphology,MORPH_TOPHAT,kernal); imshow("xuenai_morphology",xuenai_morphology); waitKet();
7.6 黑帽
原理
对输入图片先进行闭操作,然后闭操作图-原图。可以用来提取与滤波器大小相当的暗部。
效果
Mat xuenai = imread("xuenai.jpg"); Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); Mat xuenai_threshold(xuenai.size(),xuenai.type()); threshold(xuenai_gray,xuenai_threshold,100,255,THRESH_BINARY); imshow("xuenai_threshold",xuenai_threshold); Mat kernal=getStructuringElement(MORPH_RECT,Size(3,3)); Mat xuenai_morphology(xuenai.size(),xuenai.type()); morphologyEx(xuenai_threshold,xuenai_morphology,MORPH_BLACKHAT,kernal); imshow("xuenai_morphology",xuenai_morphology); waitKet();
7.7 形态学梯度
原理
膨胀图与腐蚀图之差。可以用来 提取边界轮廓 ,但提取效果比不上专业的边缘检测算法。
效果
Mat xuenai = imread("xuenai.jpg"); Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); Mat xuenai_threshold(xuenai.size(),xuenai.type()); threshold(xuenai_gray,xuenai_threshold,100,255,THRESH_BINARY); imshow("xuenai_threshold",xuenai_threshold); Mat kernal=getStructuringElement(MORPH_RECT,Size(3,3)); Mat xuenai_morphology(xuenai.size(),xuenai.type()); morphologyEx(xuenai_threshold,xuenai_morphology,MORPH_GRADIENT,kernal); imshow("xuenai_morphology",xuenai_morphology); waitKet();
7.8 击中击不中变换
原理
击中击不中变换由下面三步构成:
用结构元素B1来腐蚀输入图像
用结构元素B2来腐蚀输入图像的补集
前两步结果的与运算
结构元素B1和B2可以结合为一个元素B。例如:
结构元素:左B1(击中元素),中B2(击不中元素),右B(两者结合)
本例中,我们寻找这样一种结构模式,中间像素属于背景,其上下左右属于前景,其余领域像素忽略不计(背景为黑色,前景为白色)。然后用上面的核在输入图像中找这种结构。从下面的输出图像中可以看到,输入图像中只有一个位置满足要求。
输入二值图像
输出二值图像
8.边缘检测:选择合适的输出深度
- 参照以下表格
int sdepth | int ddepth |
---|---|
CV_8U | CV_16S/CV_32F/CV_64F |
CV_16U/CV_16S | CV_32F/CV_64F |
CV_32F | CV_32F/CV_64F |
CV_64F | CV_64F |
8.1 normalize归一化函数
CV_EXPORTS_W void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入数组 |
dst(destination) | 输出数组 |
alpha | 如果norm_type为NORM_MINMAX ,则alpha为最小值或最大值;如果norm_type为其他类型,则为归一化要乘的系数 |
beta | 如果norm_type为NORM_MINMAX ,则beta为最小值或最大值;如果norm_type为其他类型,beta被忽略. |
norm_type | 归一化类型,详见下面的内容 |
iterations | 执行erode函数的次数,默认执行一次 |
dtype | 输出数组的深度,若输入-1则表示与src一致。如果不能判断需要的深度,则可以输入-1然后使用convertScaleAbs绝对值化,这也是最推荐的做法,而不推荐自己判断深度。 |
mask | 掩码,用于指示函数是否仅仅对指定的元素进行操作。大小必须与src保持一致。具体用法见8.1.4 |
归一化类型(只介绍常用的四种)
enum NormTypes { NORM_INF = 1, NORM_L1 = 2, NORM_L2 = 4, NORM_L2SQR = 5, NORM_HAMMING = 6, NORM_HAMMING2 = 7, NORM_TYPE_MASK = 7, //!< bit-mask which can be used to separate norm type from norm flags NORM_RELATIVE = 8, //!< flag NORM_MINMAX = 32 //!< flag };
- NORM_L1
P=Ai∑∣Ai∣⋅alpha P=\frac{A_i}{\sum\left | A_i \right | } \cdot alpha P=∑∣Ai∣Ai⋅alpha
- NORM_L2
P=Ai∑Ai2⋅alpha P=\frac{A_i}{ \sqrt{\sum A_i^2} } \cdot alpha P=∑Ai2Ai⋅alpha
- NORM_INF
P=Aimax∣Ai∣⋅alpha P=\frac{A_i}{ \max \left | A_i \right | } \cdot alpha P=max∣Ai∣Ai⋅alpha
- NORM_MINMAX(recommended)
P=AkmaxAi−minAi⋅∣alpha−beta∣+min(alpha,beta) P=\frac{A_k}{ \max A_i - \min A_i } \cdot \left | alpha-beta \right | + \min(alpha,beta) P=maxAi−minAiAk⋅∣alpha−beta∣+min(alpha,beta)
8.2 convertScaleAbs绝对值化
CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst, double alpha = 1, double beta = 0);
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片 |
dst(destination) | 输出图片 |
9.sobel(对灰度图)
9.1 卷积核形状(ksize=3)
Mat kernalX=Mat_<int>(Size(3,3))<<(-1,0,1 -2,0,2 -1,0,1); Mat kernalY=Mat_<int>(Size(3,3))<<(-1,-2,1 0,0,0 1,2,1);
9.2 API
CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize = 3, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片,数据类型Mat |
dst(destination) | 输出图片,数据类型Mat |
ddepth(destination depth) | 输出图片的深度(CV_16F) |
dx | x方向导数的阶数,一般取1 |
dy | y方向导数的阶数,一般取1 |
ksize(kernal size) | 卷积核边长,默认为3 |
scale | 生成图与原图的缩放比例,默认为1 |
delta | 额外的增量,默认为0 |
borderType | 边界填充方式,默认为黑边 |
9.3 流程
- 用cvtColor函数转灰度图
- 在x,y方向上分别各调用一次Sobel
- 用convertScaleAbs函数转换到CV_8U,否则无法显示
- 用addWeighted函数把两张输出图片加在一起
9.4 同时在x,y方向上调用Sobel和分开调用的效果对比
Mat xuenai = imread("xuenai.jpg"); imshow("xuenai", xuenai); //转灰度图 Mat xuenai_gray(xuenai.size(),xuenai.type()); cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY); //同时在x,y方向上调用Sobel Mat xuenai_sobel1(xuenai.size(),xuenai.type()); Sobel(xuenai_gray,xuenai_sobel1,CV_16S,1,1,3); convertScaleAbs(xuenai_sobel1,xuenai_sobel1); imshow("xuenai_sobel1",xuenai_sobel1); //在x,y方向上分别各调用一次Sobel Mat xuenai_xsobel(xuenai.size(),xuenai.type());Mat xuenai_ysobel(xuenai.size(),xuenai.type());Mat xuenai_sobel2(xuenai.size(),xuenai.type()); Sobel(xuenai_gray,xuenai_xsobel,CV_16S,1,0,3); convertScaleAbs(xuenai_xsobel,xuenai_xsobel); Sobel(xuenai_gray,xuenai_ysobel,CV_16S,0,1,3); convertScaleAbs(xuenai_ysobel,xuenai_ysobel); addWeighted(xuenai_xsobel,0.5,xuenai_ysobel,0.5,0,xuenai_sobel2); imshow("xuenai_sobel2",xuenai_sobel2); waitKey();
可以看到效果差了很多
10.scharr(对灰度图)
10.1 卷积核形状(ksize恒定为3)
虽然Sobel算子可以有效的提取图像边缘,但是对图像中较弱的边缘提取效果较差。因此为了能够有效的提取出较弱的边缘,需要将像素值间的差距增大,因此引入Scharr算子。Scharr算子是对Sobel算子差异性的增强,因此两者之间的在检测图像边缘的原理和使用方式上相同。
Mat kernalX=Mat_<int>(Size(3,3))<<(-3,0,3 -10,0,10 -3,0,3); Mat kernalY=Mat_<int>(Size(3,3))<<(-3,-10,3 0,0,0 3,10,3);
10.2 API
CV_EXPORTS_W void Scharr( InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片,数据类型Mat |
dst(destination) | 输出图片,数据类型Mat |
ddepth(destination depth) | 输出图片的深度(CV_16F) |
dx | x方向导数的阶数,一般取1 |
dy | y方向导数的阶数,一般取1 |
scale | 生成图与原图的缩放比例,默认为1 |
delta | 额外的增量,默认为0 |
borderType | 边界填充方式,默认为黑边 |
10.3 流程
- 用cvtColor函数转灰度图
- 在x,y方向上分别各调用一次Scharr
- 用convertScaleAbs函数转换到CV_8U,否则无法显示
- 用addWeighted函数把两张输出图片加在一起
11.Laplacian(对灰度图)
11.1 卷积核形状(ksize=3)
Mat kernal=Mat_<int>(Size(3,3))<<(0,-1,0 -1,4,-1 0,-1,0);
Laplacian算子的卷积核形状决定了它 对噪声非常敏感 ,因此,通常需要通过 滤波平滑处理 。
11.2 API
CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth, int ksize = 1, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT );
- 参数如下
参数 | 含义 |
---|---|
src(source) | 输入图片,数据类型Mat |
dst(destination) | 输出图片,数据类型Mat |
ddepth(destination depth) | 输出图片的深度(CV_16F) |
scale | 生成图与原图的缩放比例,默认为1 |
delta | 额外的增量,默认为0 |
borderType | 边界填充方式,默认为黑边 |
11.3 流程
- 用中值滤波等操作平滑处理
- 用cvtColor函数转灰度图
- 用Laplacian函数处理
- 用convertScaleAbs函数转换到CV_8U,否则无法显示
12.Canny(recommended)
12.1 API
CV_EXPORTS_W void Canny( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false );
- 参数如下
参数 | 含义 |
---|---|
image | 输入图片,数据类型Mat |
edges | 输出图片,数据类型Mat |
threshold1 | 最小阈值 |
threshold2 | 最大阈值 |
apertureSize | Sobel卷积核的大小,默认为3。核越大,对噪声越不敏感,但是边缘检测的错误也会随之增加 |
L2gradient | 计算图像梯度幅度的标识,默认为false,表示L1范数(直接将两个方向的导数的绝对值相加)。如果使用true,表示L2范数(两个方向的导数的平方和再开方) |
- 高于threshold2被认为是真边界,低于threshold1被抛弃,介于二者之间,则取决于是否与真边界相连。
12.2 流程
- 用中值滤波等操作平滑处理
- 用Canny函数处理 (不支持原地运算)
12.3 效果
Mat xuenai = imread("xuenai.jpg"); imshow("xuenai",xuenai); Mat xuenai_canny(xuenai.size(),xuenai.type()); Canny(xuenai,xuenai_canny,60,150); imshow("xuenai_canny",xuenai_canny); waitKet();
13.添加噪声
为了检测算法的稳定性,常常需要在图片中人为地添加一些噪声来进行检验。
13.1 椒盐噪声
static void addSaltNoise(const Mat& src,Mat& dst,int num=1000) { dst=src.clone(); for (int k = 0; k < num; k++) { //随机取值行列,得到像素点(i,j) int i = rand() % dst.rows; int j = rand() % dst.cols; //修改像素点(i,j)的像素值 for(int channel=0;channel<src.channels();channel++){ dst.ptr(i,j)[channel]=255; } } for (int k = 0; k < num; k++) { //随机取值行列 default_random_engine engine; uniform_int_distribution<unsigned>u(0,10000); int i = rand() % dst.rows; int j = rand() % dst.cols; //修改像素点(i,j)的像素值 for(int channel=0;channel<src.channels();channel++){ dst.ptr(i,j)[channel]=0; } } return; }
src(source):输入图片
dst(destination):输出图片
num(number):噪声的个数
13.2 高斯噪声
static void addGaussianNoise(const Mat& src,Mat& dst,InputArray meanValue=10,InputArray std=36){ dst=src.clone(); //构造高斯噪声矩阵 Mat noise(dst.size(),dst.type()); RNG rng(time(NULL)); rng.fill(noise, RNG::NORMAL, meanValue, std); //将高斯噪声矩阵与原图像叠加得到含噪图像 dst+=noise; return ; }
src(source):输入图片
dst(destination):输出图片
meanValue:高斯函数均值
std(standard deviation):高斯函数标准差
随机数填充矩阵
void RNG::fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange = false );
- 参数如下
参数 | 含义 |
---|---|
mat | 输入输出矩阵,最多支持4通道,超过4通道先用reshape()改变结构 |
distType(distination type) | 可选UNIFORM 或 NORMAL,分别表示均匀分布和高斯分布 |
a | disType是UNIFORM,a表示下界(闭区间);disType是NORMAL,a表示均值 |
b | disType是UNIFORM,b表示上界(开区间);disType是NORMAL,b表示标准差 |
saturateRange | 只针对均匀分布有效。当为真的时候,会先把产生随机数的范围变换到数据类型的范围,再产生随机数;如果为假,会先产生随机数,再进行截断到数据类型的有效区间。 |
本文由博客一文多发平台 OpenWrite 发布!
这篇关于【OpenCV教程】滤波和边缘检测的过程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-20获取apk的md5值有哪些方法?-icode9专业技术文章分享
- 2024-11-20xml报文没有传 IdentCode ,为什么正常解析没报错呢?-icode9专业技术文章分享
- 2024-11-20如何知道代码有没有进行 Schema 验证?-icode9专业技术文章分享
- 2024-11-20Mycat教程:新手快速入门指南
- 2024-11-20WebSocket入门:轻松掌握WebSocket基础
- 2024-11-19WebSocket入门指南:轻松搭建实时通信应用
- 2024-11-19Nacos安装资料详解:新手入门教程
- 2024-11-19Nacos安装资料:新手入门教程
- 2024-11-19升级 Gerrit 时有哪些注意事项?-icode9专业技术文章分享
- 2024-11-19pnpm是什么?-icode9专业技术文章分享