《Learning Opencv3》第十章 滤波和卷积

第十章 滤波和卷积(一)

一、卷积

**卷积convolution:**对图像的操作;

卷积核kernel:一个矩阵,用于卷积运算,一般中心是锚点anchor point

**填充pad:**由于卷积时边缘像素没有被卷积核覆盖,所以会有边缘问题。所以在卷积之前,需要对原图像进行边缘填充。

int cv::borderInterpolate(       // Returns coordinate of "donor" pixel
  int p,                         // 0-based coordinate of extrapolated pixel
  int len,                       // Length of array (on relevant axis)
  int borderType                 // Pixel extrapolation method
);

填充方式:

BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh

BORDER_REFLECT: fedcba|abcdefgh|hgfedcb

BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba

BORDER_WRAP: cdefgh|abcdefgh|abcdefg

BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified ‘i’

在这里插入图片描述

二、阈值化操作

2.1 阈值化

阈值化操作就是要从图像中分离对象(前景和背景分离)。

double cv::threshold(
  cv::InputArray    src,             // Input image
  cv::OutputArray   dst,             // Result image
  double            thresh,          // Threshold value
  double            maxValue,        // Max value for upward operations
  int               thresholdType    // Threshold type
);

阈值化操作有如下:

THRESH_BINARY二进制阈值化

THRESH_BINARY_INV反二进制阈值化

THRESH_TRUNC截断阈值化

THRESH_TOZERO阈值化为0

THRESH_TOZERO_INV反阈值化为0

在这里插入图片描述

void sum_rgb(const Mat& src, Mat& dst) {
	// Split image onto the color planes.
	vector< Mat> planes;
	split(src, planes);
	Mat b = planes[0], g = planes[1], r = planes[2], s;

	// Add equally weighted rgb values.
	addWeighted(r, 1. / 3., g, 1. / 3., 0.0, s);
	addWeighted(s, 1., b, 1. / 3., 0.0, s);

	// Truncate values above 100.
	threshold(s, dst, 100, 100, THRESH_TRUNC);
}

int main() {
	Mat src = imread("1.jpg"), dst;
	imshow("org img", src);

	sum_rgb(src, dst);
	imshow("dst img", dst);

	waitKey(0);
	return 0;
}

在这里插入图片描述
之所以要把三个颜色的通道分开是因为,高位容易溢出?(没看懂)

2.2 Otsu算法

σ w 2 = w 1 ( t ) σ 1 2 + w 2 ( t ) σ 2 2 \sigma_{w}^{2}=w_{1}(t)\sigma_{1}^{2}+w_{2}(t)\sigma_{2}^{2} σw2=w1(t)σ12+w2(t)σ22

两类像素方差的权值由两类像素的个数决定。这种阈值化的结果相对来说比较理想,可以避免寻找合适阈值的操作,但是这种方式运算量较大,费时。

2.3 自适应阈值

在图像阈值化操作中,我们更关心的是从二值化图像中分离目标区域和背景区域,仅仅通过固定阈值很难达到理想的分割效果。在图片中的灰度是不均匀的,所以通常情况下图片中不同区域的阈值时不一样的。

自适应阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。


void cv::adaptiveThreshold(
	cv::InputArray src, // 输入图像
	cv::OutputArray dst, // 输出图像
	double maxValue, // 向上最大值
	int adaptiveMethod, // 自适应方法,平均或高斯
	int thresholdType // 阈值化类型
	int blockSize, // 块大小
	double C // 常量
);
int main() {
	Mat src = imread("2.jpg", IMREAD_GRAYSCALE);
	Mat dst;
	imshow("src img", src);
    
	int maxVal = 255;
	int blockSize = 53;
	double C = 0;

	adaptiveThreshold(src, dst, maxVal, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, blockSize, C);
	imshow("threshold", dst);
	waitKey(0);
	return 0;
}

在这里插入图片描述

三、平滑(模糊)

作用:减少噪声、降低分辨率。

OpenCV提供了五种平滑方式。

3.1 均值滤波(box filter)

void cv::blur(
  cv::InputArray  src,                            // Input image
  cv::OutputArray dst,                            // Result image
  cv::Size        ksize,                          // Kernel size(滤波器的大小)
  cv::Point       anchor     = cv::Point(-1,-1),  // Location of anchor point(锚点,被平滑点,默认是负值取中心)
  int             borderType = cv::BORDER_DEFAULT // Border extrapolation to use(边缘)
);
void cv::boxFilter(
  cv::InputArray  src,                            // Input image
  cv::OutputArray dst,                            // Result image
  int             ddepth,                         // Output depth (e.g., CV_8U),输出图像的深度,-1代表使用原图深度
  cv::Size        ksize,                          // Kernel size
  cv::Point       anchor     = cv::Point(-1,-1),  // Location of anchor point
  bool            normalize  = true,              // If true, divide by box area,表示内核是否被其区域归一化(normalized)了
  int             borderType = cv::BORDER_DEFAULT // Border extrapolation to use
);

在这里插入图片描述
在这里插入图片描述

3.2 均值滤波(Median filter)

均值滤波就是把将像素的数据从小到大排序,如何取中间值。

有效去除椒盐噪声

c++void cv::medianBlur(
  cv::InputArray  src,                 // Input image
  cv::OutputArray dst,                 // Result image
  cv::Size        ksize                // Kernel size
);

在这里插入图片描述

3.3 高斯噪声(Gaussian filter)

高斯滤波就是对整幅图像进行加权平均,注意此处是高斯低通滤波器。

有效消除高斯噪声

void cv::GaussianBlur(
  cv::InputArray  src,                     // Input image
  cv::OutputArray dst,                     // Result image
  cv::Size        ksize,                   // Kernel size
  double          sigmaX,                  // Gaussian half-width in x-direction
  double          sigmaY     = 0.0,        // Gaussian half-width in y-direction
  int             borderType = cv::BORDER_DEFAULT // Border extrapolation to use
);

在这里插入图片描述
在这里插入图片描述

3.4 双边滤波(Bilateral filter)

双边滤波和高斯滤波很相似,但是有两个权值,第一个和高斯滤波一样,是像素值的权值,第二个是考虑相对于中心像素的空间距离得到的权值。通俗来说,双边滤波就是相似的像素点比不相似的权值更高,从而让边缘锐化(边缘不模糊),而且还能够去除噪声。

void cv::bilateralFilter(
  cv::InputArray  src,             // Input image
  cv::OutputArray dst,             // Result image
  int             d,               // Pixel neighborhood size (max distance)
  double          sigmaColor,      // Width param for color weight function,颜色空间滤波器的sigma值。方差越大,权重差别越小,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
  double          sigmaSpace,      // Width param for spatial weight function,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色
  int             borderType = cv::BORDER_DEFAULT  // Border extrapolation to use
);

在这里插入图片描述
在这里插入图片描述

四、导数(Deriviative)和梯度(Gradient)

求导数也是卷积的一种,现在有很多求导的方法,但是只有少部分能够很好的应用在实际中。

4.1 Sobel导数

Sobel算子定义在离散的空间上,所以称Sobel算子是严格的求导。Sobel算子是对多项式的拟合,也就是说Sobel算子中xorder=2,并不是求二阶导数,而是对抛物线的拟合。这也就解释了为什么需要更大的卷积核,因为卷积核大在很多像素的情况下拟合的更好,卷积核小会对噪声比较敏感。

需要注意的是,如果源图像是8位的,目标图像的深度至少应该是CV_16S,因为可能会溢出。

void cv::Sobel(
  cv::InputArray  src,                 // Input image
  cv::OutputArray dst,                 // Result image
  int             ddepth,              // Pixel depth of output (e.g., CV_8U)
  int             xorder,              // order of corresponding derivative in x(阶数)
  int             yorder,              // order of corresponding derivative in y(阶数)
    //xorder和yorder一般是0,1,2
  cv::Size        ksize      = 3,      // Kernel size(odd)
  double          scale      = 1,      // Scale (applied before assignment)
  double          delta      = 0,      // Offset (applied before assignment)
  int             borderType = cv::BORDER_DEFAULT  // Border extrapolation
);

在这里插入图片描述

4.2 Scharr滤波

Scharr仅作用于3x3大小的内核。具有和sobel算子一样的速度,但结果更为精确。Scharr算子与Sobel的不同在于中心像素的权重更大,这可能是相对于图像这种随机性较强的信号,邻域相关性不大,所以邻域平滑应该使用相对较小的标准差的高斯函数,也就是更瘦高的模板

在这里插入图片描述

4.3 Laplacian算子

Laplace的函数和Sobel的函数参数很相似,至少其中的orders(阶数)没有,这是因为Laplacian很像二阶Sobel算子。

Laplacian算子可以检测边缘。

void cv::Laplacian(
  cv::InputArray  src,                 // Input image
  cv::OutputArray dst,                 // Result image
  int             ddepth,              // Depth of output image (e.g., CV_8U)
  cv::Size        ksize      = 3,      // Kernel size
  double          scale      = 1,      // Scale applied before assignment to dst
  double          delta      = 0,      // Offset applied before assignment to dst
  int             borderType = cv::BORDER_DEFAULT  // Border extrapolation to use
);

注意ksize=1。

在这里插入图片描述
在这里插入图片描述
但是在棋盘的图上表现较为糟糕。

在这里插入图片描述

五、图像形态学

所有的图像形态学操作都是建立在两种运算上,腐蚀(erosion)和膨胀(dilation),这些都是卷积运算!

以下是所有的形态学操作:

在这里插入图片描述

5.1 膨胀(Dilation)和腐蚀(Erosion)

作用:

1、减少噪声

2、分割独立元素(isolating individual elements)

3、连接不同的元素(joining disparate elemets)

4、复杂的形态学操作还可以:找到一幅图像密度的最大值和最小值

5、求形态学梯度

**膨胀(Dilation):**保留卷积核中的最大值像素,是非线性的操作,所以卷积核不能像之前那样表示。

**效果:**将图像光亮部分放大,黑暗部分缩小。

**作用:**可以用来填补物体中的空洞。

**腐蚀(Erosion):**保留局部最小值。

**效果:**将图像黑暗部分放大,光亮部分缩小。

**作用:**消除小于结构元素的噪声点

void cv::erode(
  cv::InputArray    src,                              // Input image
  cv::OutputArray   dst,                              // Result image
  cv::InputArray    element,                          // Structuring, a cv::Mat()
  cv::Point         anchor      = cv::Point(-1,-1),   // Location of anchor point
  int               iterations  = 1,                  // Number of times to apply
  int               borderType  = cv::BORDER_CONSTANT // Border extrapolation
  const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue()
);
void cv::dilate(
  cv::InputArray    src,               // Input image
  cv::OutputArray   dst,               // Result image
  cv::InputArray    element,                          // Structuring, a cv::Mat()
  cv::Point         anchor      = cv::Point(-1,-1),   // Location of anchor point
  int               iterations  = 1,                  // Number of times to apply
  int               borderType  = cv::BORDER_CONSTANT // Border extrapolation
  const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue()
);
int main() {
	Mat src = imread("1.jpg", IMREAD_GRAYSCALE);
	Mat dst;
	imshow("src img", src);
	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
	erode(src, dst, element);
	
	imshow("erode", dst);
	waitKey(0);
	return 0;
}

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值