天天看点

OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

文章目录

  • ​​一、图像滤波​​
  • ​​均值滤波​​
  • ​​中值滤波​​
  • ​​高斯滤波​​
  • ​​双边滤波​​
  • ​​二、卷积运算符 filter2D​​
  • ​​三、边缘处理​​

关于更多滤波详情:

​​OpenCV—Python 图像滤波(均值、中值、高斯、高斯双边、高通等滤波)​​

一、图像滤波

头文件 ​

​quick_opencv.h​

​:声明类与公共函数

#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
public:
    ...
    void blur_Demo(Mat& image);
    void medianblur_Demo(Mat& image);
    void gaussian_Demo(Mat& image);
    void bilateralFilter_Demo(Mat& image);

    void custom_mask_Demo(Mat& image); //自定义掩膜运算
    void edge_process_Demo(Mat& image1);

};      

主函数调用该类的公共成员函数

#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;


int main(int argc, char** argv) {
  Mat src = imread("D:\\Desktop\\pandas.jpg");
  if (src.empty()) {
    printf("Could not load images...\n");
    return -1;
  }
  namedWindow("input", WINDOW_NORMAL);
  imshow("input", src);

  QuickDemo qk;

  ...
  qk.blur_Demo(src);
  qk.medianblur_Demo(src);
  qk.gaussian_Demo(src);
  qk.bilateralFilter_Demo(src);
  qk.custom_mask_Demo(src);
  qk.edge_process_Demo(src1);
  waitKey(0);
  destroyAllWindows();
  return 0;
}      

均值滤波

目的与原理

  • 目的:去除图像上的尖锐噪声,平滑图像。
  • 原理:均值滤波属于线性滤波,它的实现原理是邻域平均法。

源文件 ​

​quick_demo.cpp​

​:实现类与公共函数

void QuickDemo::blur_Demo(Mat& image) {
  Mat dst, dst1, dst2;
  blur(image, dst, Size(5, 5), Point(-1, -1));
  blur(image, dst1, Size(15, 1), Point(-1, -1));
  blur(image, dst2, Size(1, 15), Point(-1, -1));
  imshow("均值滤波", dst);
  imshow("横向滤波", dst1);
  imshow("竖直滤波", dst2);
}      
OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

中值滤波

统计排序滤波器

中值对椒盐噪声有很好的抑制作用

void QuickDemo::medianblur_Demo(Mat& image) {
  Mat dst, dst1, dst2;
  medianBlur(image.clone(), dst, (3, 3));
  medianBlur(image.clone(), dst1, (5, 5));
  medianBlur(image.clone(), dst2, (7, 7));
  imshow("中值滤波", dst);
  imshow("中值滤波1", dst1);
  imshow("中值滤波2", dst2);
}      
OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

高斯滤波

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。

高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。

高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。

OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理
OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

源文件 ​

​quick_demo.cpp​

​:实现类与公共函数

void QuickDemo::gaussian_Demo(Mat& image) {
  Mat dst;
  GaussianBlur(image, dst, Size(5, 5), 15);
  imshow("高斯滤波", dst);
}      

双边滤波

边缘保留滤波算法:

  • 高斯双边滤波
  • Meanshift均值迁移模糊
  • 局部均方差模糊
  • 导向滤波

双边滤波的原理示意图:

OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

InputArray

src,    输入图像

OutputArray

dst,   目标图像,需要和源图片有一样的尺寸和类型

int

d,        在过滤期间使用的每个像素邻域的直径。如果输入d非0(没输入),则sigmaSpace由d计算得出。

double

sigmaColor,  颜色空间滤波器的sigma值,这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。

double

sigmaSpace, 坐标空间滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。

int

borderType = BORDER_DEFAULT  图像边界模式

)

void QuickDemo::bilateralFilter_Demo(Mat& image) {
  Mat dst;
  bilateralFilter(image, dst, 0, 100.0, 10.0);
  imshow("双边滤波", dst);
}      
OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

二、卷积运算符 filter2D

使用锐化掩膜测试:

OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

自定义掩膜:

Mat kernel_ = (Mat_<char>(3, 3) << 0, -1, 0, 
                    -1, 5, -1, 
                               0, -1, 0);      

InputArray src,     输入图像

OutputArray dst,     输出图像,和输入图像具有相同的尺寸和通道数量

int ddepth,      目标图像深度,为-1时保持输入图像通道深度

InputArray kernel,    卷积核

Point anchor=Point(-1,-1),表示过滤点在内核中的相对位置的内核锚;锚应位于内核内;默认值(-1,-1)表示锚点位于内核中心。

double delta=0,     在储存目标图像前可选的添加到像素的值,默认值为0

int borderType=BORDER_DEFAULT   默认值是BORDER_DEFAULT,即对全部边界进行计算。

);

计算公式:

涉及图像指针的运算等。

void QuickDemo::custom_mask_Demo(Mat& image) {
  // 自定义filter函数实现
  int offset = image.channels();
  int cols = (image.cols - 1) * offset;
  int rows = image.rows;
  Mat dst = Mat::zeros(image.size(), image.type());
  for (int row = 1; row < (rows - 1); row++) {
    const uchar* previous = image.ptr<uchar>(row-1);
    const uchar* current = image.ptr<uchar>(row);
    const uchar* next = image.ptr<uchar>(row+1);
    uchar* output = dst.ptr<uchar>(row);
    for (int col = offset; col < cols; col++) {
      output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offset] + current[col + offset] + previous[col] + next[col]));
    }
  }
  imshow("dst", dst);

  // opencv自带filter2D函数实现
  Mat dst2;
  Mat kernel_ = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
  filter2D(image.clone(), dst2, image.depth(), kernel_);
  imshow("dst2", dst2);
}      

可以看出dst2没有黑边了,边缘被处理了。

OpenCV + CPP 系列(二十)图像卷积一(均值、中值、高斯、双边滤波)与 边缘处理

关于更多请点击查看 ​​OpenCV + CPP 系列(廿一)图像卷积二 (sobel、laplance、canny)边缘提取​​

更多关于双边滤波 ​​https://zhuanlan.zhihu.com/p/127023952​​

三、边缘处理

在卷积开始之前增加边缘像素,填充的像素值为0或者RGB黑色,比如3x3在

四周各填充1个像素的边缘,在卷积处理之后再去掉这些边缘,这样就确保图像的边缘被处理。

void copyMakeBorder(

InputArray src,     // 输入图像

OutputArray dst,  // 输出图像

int top,       // 填充边缘长度,一般上下左右都取相同值

int bottom,

int left,

int right,

int borderType,   // 填充类型

const Scalar& value = Scalar() // 边框颜色值,边框类型=BUALE_CONTER时才有用

)

openCV中的处理方法是:

  • BORDER_DEFAULT  - 默认的处理(镜像边界像素:1234|4321)
  • BORDER_CONSTANT – 填充边缘用指定像素值
  • BORDER_REPLICATE – 填充边缘像素用已知的边缘像素值。(复制边界像素:1234|4444)
  • BORDER_WRAP – 用另外一边的像素来补偿填充

使用参数

  • BORDER_CONSTANT = 0

    BORDER_REPLICATE = 1

    BORDER_REFLECT = 2

    BORDER_REFLECT_101 = 4,

    BORDER_REFLECT101 = BORDER_REFLECT_101,

    BORDER_DEFAULT = BORDER_REFLECT_101,

    BORDER_WRAP = 3,

    BORDER_TRANSPARENT = 5,

void QuickDemo::edge_process_Demo(Mat& image) {
  Mat dst0, dst1;
  copyMakeBorder(image, dst0, 5, 5, 5, 5, BORDER_REFLECT);
  copyMakeBorder(image, dst1, 5, 5, 5, 5, BORDER_CONSTANT,Scalar(0,255,255));
  imshow("REFLECT", dst0);
  imshow("CONSTANT", dst1);
}      

继续阅读