【OpenCV教程】滤波和边缘检测的过程

news/2024/11/16 5:48:00/文章来源:https://www.cnblogs.com/UnderTurrets/p/18367899

@

目录
  • 1.均值滤波
    • 1.1 卷积核形状
    • 1.2 API
    • 1.3 效果
  • 2.高斯滤波
    • 2.1 卷积核形状
    • 2.2 API
    • 2.3 效果
  • 3.中值滤波
    • 3.1 原理
    • 3.2 API
    • 3.3 效果
  • 4.高斯双边滤波
    • 4.1 原理
    • 4.2 API
    • 4.3 效果
  • 5.获取用来形态学操作的滤波器
  • 6.腐蚀和膨胀(对二值图)
    • 6.1 原理
    • 6.2 腐蚀API
    • 6.3 效果
    • 6.4 膨胀API
    • 6.5 效果
  • 7.形态学操作(对二值图)
    • 7.1 API
    • 7.2 变换类型
    • 7.3 开
      • 原理
      • 效果
    • 7.4 闭
      • 原理
      • 效果
    • 7.5 顶帽
      • 原理
      • 效果
    • 7.6 黑帽
      • 原理
      • 效果
    • 7.7 形态学梯度
      • 原理
      • 效果
    • 7.8 击中击不中变换
      • 原理
  • 8.边缘检测:选择合适的输出深度
    • 8.1 normalize归一化函数
      • 归一化类型(只介绍常用的四种)
    • 8.2 convertScaleAbs绝对值化
  • 9.sobel(对灰度图)
    • 9.1 卷积核形状(ksize=3)
    • 9.2 API
    • 9.3 流程
    • 9.4 同时在x,y方向上调用Sobel和分开调用的效果对比
  • 10.scharr(对灰度图)
    • 10.1 卷积核形状(ksize恒定为3)
    • 10.2 API
    • 10.3 流程
  • 11.Laplacian(对灰度图)
    • 11.1 卷积核形状(ksize=3)
    • 11.2 API
    • 11.3 流程
  • 12.Canny(recommended)
    • 12.1 API
    • 12.2 流程
    • 12.3 效果
  • 13.添加噪声
    • 13.1 椒盐噪声
    • 13.2 高斯噪声
      • 随机数填充矩阵


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)=\frac{1}{2 \pi \sigma{2}}e){2}+(y-y_{0}){2}}{2\sigma^{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 flagsNORM_RELATIVE  = 8, //!< flagNORM_MINMAX    = 32 //!< flag
};
  • NORM_L1

$$
P=\frac{A_i}{\sum\left | A_i \right | } \cdot alpha
$$

  • NORM_L2

$$
P=\frac{A_i}{ \sqrt{\sum A_i^2} } \cdot alpha
$$

  • NORM_INF

$$
P=\frac{A_i}{ \max \left | A_i \right | } \cdot alpha
$$

  • NORM_MINMAX(recommended)

$$
P=\frac{A_k}{ \max A_i - \min A_i } \cdot \left | alpha-beta \right | + \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,10,0,01,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 流程

  1. 用cvtColor函数转灰度图
  2. 在x,y方向上分别各调用一次Sobel
  3. 用convertScaleAbs函数转换到CV_8U,否则无法显示
  4. 用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,30,0,03,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 流程

  1. 用cvtColor函数转灰度图
  2. 在x,y方向上分别各调用一次Scharr
  3. 用convertScaleAbs函数转换到CV_8U,否则无法显示
  4. 用addWeighted函数把两张输出图片加在一起

11.Laplacian(对灰度图)

11.1 卷积核形状(ksize=3)

Mat kernal=Mat_<int>(Size(3,3))<<(0,-1,0-1,4,-10,-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 流程

  1. 用中值滤波等操作平滑处理
  2. 用cvtColor函数转灰度图
  3. 用Laplacian函数处理
  4. 用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 流程

  1. 用中值滤波等操作平滑处理
  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 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/783918.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Excel公式和基本函数

输入完公式,点击回车,即可显示出值,<>是不等号

03-Matlab数组与矩阵

数组的建立和操作数组算术运算数组信息获取矩阵的建立矩阵的扩展矩阵的块操作矩阵中元素的删除赋值为一对方括号 矩阵的转置加点不转置为共轭复数 没点的转置为共轭复数 矩阵的旋转矩阵的翻转矩阵尺寸的改变矩阵加减法矩阵乘法矩阵除法矩阵中元素查找矩阵元素排序矩阵元素求和矩…

云音乐贵州机房迁移总体方案回顾

一、背景 2023年确定要将云音乐整体服务搬迁至贵州机房,项目需要在各种限制条件下,保障2000+应用、100w+QPS的服务稳定迁移,是云音乐历史上规模最大、人员最多、难度最高的技术项目。在此过程中,解决了大量历史技术债务,同时化解了大量新增系统性风险。以下为总体方案回顾…

湿式复合机剥离涂布机切纸机高静电横切机PLC数据采集系统车间联网方案

序号 设备名称 品牌/厂家 型号 数量 "系统类型" 品牌/厂家 "其他型号补充说明" "可用通讯接 口" 数采需求内容1 "复合机组(1#)" "松德机械股份有限公司" FTB1600 1 PLC "西门子PLC(SIEMENS)" S7-300 R…

关于SEGGER Embedded Studio的一些设置,自己摸索的

1. 删除Embedded Studio最近的项目 如下图所示,File->Recent Projects->Manage Recent Projects,就可以打开 Recent Projects 视图窗口,在此窗口中右键点击项目,进行删除,或者其他操作。2. Embedded Studio的启动文件问题 我原来的疑惑是Embedded Studio有自己的启动…

[开源分享]一个用于单片机IAP自动发送的串口助手,上位机,使用Python+tkinter制作

使用Python + tkinter制作。 这是个给单片机通过串口进行IAP的上位机,与单片机中的BOOT程序配合使用,完成对单片机APP程序的升级。可以完成bin文件的切片,CRC校验(使用Crc32Mpeg2),打包自动发送。使用Python + tkinter制作。 功能: 这是个给单片机通过串口进行IAP的上位…

go语言学习过程报错处理-哇哈哈哈

用学习来麻痹自己蠢蠢欲动的心。题记无聊学习ing,思考了下还是学下go语言写免杀木马吧,毕竟在我的学习计划里放了小半年了,上班的时候还没多少自己的时间学习。为什么无聊大家都懂吧,应该会懂的吧。主要还是需要分散下注意力,近期脑子整天都是奇奇怪怪的幻想,太影响人了。…

来了!2024 云栖大会正式启动

来了!2024 云栖大会正式启动

[开源分享]一个用于单片机IAP自动升级的串口助手,上位机,使用Python+tkinter制作

使用Python + tkinter制作。 这是个给单片机通过串口进行IAP的上位机,与单片机中的BOOT程序配合使用,完成对单片机APP程序的升级。可以完成bin文件的切片,CRC校验(使用Crc32Mpeg2),打包自动发送。使用Python + tkinter制作。 功能: 这是个给单片机通过串口进行IAP的上位…

资产负债率、净资产收益率如何解读?教你弄懂财务报表的关键

财务报表中包含大量的信息,如果我们在解读财务报表时没有思路,不分重点,就很容易被繁杂的数据弄得头晕眼花。本文就财务报表中的关键指标、资产负债率解读、净资产收益率分析、计算销售复合增长率等几个方面进行介绍,大家可以根据自己的需要进行选择性的学习。 一、这些指标…

程序运行异常: Modulo by zero

用户在使用PbootCMS系统时遇到一个问题,即在网站描述或栏目描述中添加百分号(%)会导致错误。其实, 解决并不复杂。 将模板中标题、描述、关键词用下面的标签替换就可以解决<title>{pboot:pagetitle}</title><meta name="keywords" content="…

java基础private/封装篇

private的使用 private 设置后 想要更改变量只能在此类中更改 若想在其他类中更改和使用需要用get/set方法 get获取变量值 set更改变量值 需自定义 方法可加判断 构造方法的概述构造方法是一种特殊的方法作用:创建对象格式:public class 类名{修饰符 类名(参数){}}修饰符一般…