学习Qt_OpenCV线型滤波种类、特点、适用范围及OpenCV实现

参考教程:https://blog.csdn.net/qingyang8513/article/details/80413320 

线型滤波
    图像平滑处理又称为图像模糊,主要是用来减少图像上的噪声点或者失真

    图像滤波是在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可或缺的操作,其处理效果的好坏将直接影响后续图像处理和分析的效率。

    图像滤波分为线型滤波非线性滤波,其中线型滤波根据滤波器特性可以分为低通滤波、高通滤波、带通滤波、带阻滤波器、全通滤波和陷波滤波等。由于图像的细节信息包含在图像的高频部分,因此低通滤波具有图像模糊的效果,而高通滤波具有图像锐化的特点。

    这里介绍的线型滤波包括方框滤波、均值滤波和高斯滤波,三者均为低通滤波,具有消除噪声,图像模糊的特点。其中,均值滤波为归一化后的方框滤波,而高斯滤波主要用来去除图像混入的高斯噪声

    这里仅介绍各滤波函数的实现方式,并通过OpenCV示例演示器效果,具体理论部分请参考相应教材或者论坛。

doc:https://docs.opencv.org/4.1.0/

3.1 方框滤波
OpenCV函数原型及参数说明:

void cv::boxFilter ( InputArray  src,
    OutputArray  dst,
    int  ddepth,
    Size  ksize,
    Point  anchor = Point(-1,-1),
    bool  normalize = true,
    int  borderType = BORDER_DEFAULT 
  )

 

#include

Blurs an image using the box filter.

The function smooths an image using the kernel:

\texttt{K} =  \alpha \begin{bmatrix} 1 & 1 & 1 &  \cdots & 1 & 1  \\ 1 & 1 & 1 &  \cdots & 1 & 1  \\ \hdotsfor{6} \\ 1 & 1 & 1 &  \cdots & 1 & 1 \end{bmatrix}

where

\alpha = \fork{\frac{1}{\texttt{ksize.width*ksize.height}}}{when \texttt{normalize=true}}{1}{otherwise}

参考:https://docs.opencv.org/4.1.0/d4/d86/group__imgproc__filter.html#gad533230ebf2d42509547d514f7d3fbc3

非标准化盒式滤波器可用于计算每个像素邻域上的各种积分特性,例如图像导数的协方差矩阵(用于密集光流算法等)。如果需要在可变大小的窗口上计算像素总和,请使用积分。

参数

SRC 输入图像。
DST 输出与src相同大小和类型的图像。
ddepth 输出图像深度(-1使用src.depth())。
ksize 模糊内核大小。
锚点; 默认值Point(-1,-1)表示锚点位于内核中心。
正常化 flag,指定内核是否按其区域进行规范化。
borderType 用于外推图像外部像素的边框模式,请参阅BorderTypes

 

3.2 均值滤波

OpenCV函数原型及参数说明:

void cv::blur ( InputArray  src,
    OutputArray  dst,
    Size  ksize,
    Point  anchor = Point(-1,-1),
    int  borderType = BORDER_DEFAULT 
  )  

#include

使用标准化的盒式过滤器模糊图像。

该函数使用内核平滑图像:

\texttt{K} =  \frac{1}{\texttt{ksize.width*ksize.height}} \begin{bmatrix} 1 & 1 & 1 &  \cdots & 1 & 1  \\ 1 & 1 & 1 &  \cdots & 1 & 1  \\ \hdotsfor{6} \\ 1 & 1 & 1 &  \cdots & 1 & 1  \\ \end{bmatrix}

参数

SRC 输入图像; 它可以有任意数量的通道,这些通道是独立处理的,但深度应该是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
DST 输出与src相同大小和类型的图像。
ksize 模糊内核大小。
锚点; 默认值Point(-1,-1)表示锚点位于内核中心。
borderType 用于外推图像外部像素的边框模式,请参阅BorderTypes

 

3.3 高斯滤波

OpenCV函数原型及参数说明:

void cv::GaussianBlur ( InputArray  src,
    OutputArray  dst,
    Size  ksize,
    double  sigmaX,
    double  sigmaY = 0,
    int  borderType = BORDER_DEFAULT 
  )  

#include

使用高斯滤波器模糊图像。

该函数将源图像与指定的高斯内核进行卷积。支持就地过滤。

参数

SRC 输入图像; 图像可以有任意数量的通道,这些通道是独立处理的,但深度应该是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
DST 输出与src相同大小和类型的图像。
ksize 高斯核大小。ksize.width和ksize.height可以不同,但​​它们都必须是正数和奇数。或者,它们可以是零,然后它们是从西格玛计算的。
sigmaX X方向的高斯核标准偏差。
sigmaY Y方向的高斯核标准偏差; 如果sigmaY为零,则将其设置为等于sigmaX,如果两个sigma均为零,则分别从ksize.width和ksize.height计算(有关详细信息,请参阅getGaussianKernel); 为了完全控制结果,无论将来可能修改所有这些语义,建议指定所有ksize,sigmaX和sigmaY。
borderType 像素外推法,参见BorderTypes

参考:https://docs.opencv.org/4.1.0/d4/d86/group__imgproc__filter.html#gaabe8c836e97159a9193fb0b11ac52cf1

设计图示

学习Qt_OpenCV线型滤波种类、特点、适用范围及OpenCV实现_第1张图片

初始界面

学习Qt_OpenCV线型滤波种类、特点、适用范围及OpenCV实现_第2张图片

原始图片效果:

学习Qt_OpenCV线型滤波种类、特点、适用范围及OpenCV实现_第3张图片

分别调整至最大:

学习Qt_OpenCV线型滤波种类、特点、适用范围及OpenCV实现_第4张图片

一起调整的效果:学习Qt_OpenCV线型滤波种类、特点、适用范围及OpenCV实现_第5张图片

mainwindow.ui



 MainWindow
 
  
   
    0
    0
    791
    542
   
  
  
   MainWindow
  
  
   
    
     
      380
      350
      141
      21
     
    
    
     label_Kernel_BoxFilter
    
   
   
    
     
      380
      370
      111
      31
     
    
    
     label_Kernel_Blur
    
   
   
    
     
      380
      400
      161
      41
     
    
    
     label_Kernel_GuassianBlur
    
   
   
    
     
      690
      450
      75
      23
     
    
    
     打开图像
    
   
   
    
     
      550
      410
      101
      20
     
    
    
     Qt::Horizontal
    
   
   
    
     
      550
      350
      101
      19
     
    
    
     Qt::Horizontal
    
   
   
    
     
      550
      380
      101
      19
     
    
    
     Qt::Horizontal
    
   
   
    
     
      380
      450
      101
      16
     
    
    
     label_Kernel_All
    
   
   
    
     
      550
      440
      101
      19
     
    
    
     Qt::Horizontal
    
   
   
    
     
      50
      60
      271
      181
     
    
    
     label_Display1
    
   
   
    
     
      380
      50
      271
      181
     
    
    
     label_Display2
    
   
   
    
     
      40
      270
      271
      181
     
    
    
     label_Display3
    
   
   
    
     
      50
      30
      141
      21
     
    
    
     方框滤波boxFilter
    
   
   
    
     
      380
      30
      141
      21
     
    
    
     均值滤波Blur
    
   
   
    
     
      50
      240
      141
      21
     
    
    
     高斯滤波GaussianBlur
    
   
  
  
   
    
     0
     0
     791
     23
    
   
  
  
   
    TopToolBarArea
   
   
    false
   
  
  
 
 
 
 

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 
#include 

#define KERNEL_MIN_VALUE    0
#define KERNEL_MAX_VALUE    40

Mat g_srcImage;
Mat g_dstImage_BoxFilter;
Mat g_dstImage_Blur;
Mat g_dstImage_GaussianBlur;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->menuBar->hide();    //隐藏菜单栏
    ui->mainToolBar->hide();//隐藏工具栏
    ui->statusBar->hide();  //隐藏状态栏
    setWindowTitle(tr("Qt_OpenCV线型滤波"));

    //初始化变量
    m_kernelValueBoxFilter = 3;
    m_kernelValueBlur = 3;
    m_kernelValueGaussianBlur = 3;
    m_kernelAll = 3;
    m_isOpenFile = false;

    //初始化控件
    ui->horizontalSlider_BoxFilter->setMinimum(KERNEL_MIN_VALUE);
    ui->horizontalSlider_BoxFilter->setMaximum(KERNEL_MAX_VALUE);
    ui->horizontalSlider_BoxFilter->setValue(m_kernelValueBoxFilter);

    ui->horizontalSlider_Blur->setMinimum(KERNEL_MIN_VALUE);
    ui->horizontalSlider_Blur->setMaximum(KERNEL_MAX_VALUE);
    ui->horizontalSlider_Blur->setValue(m_kernelValueBlur);

    ui->horizontalSlider_GaussianBlur->setMinimum(KERNEL_MIN_VALUE);
    ui->horizontalSlider_GaussianBlur->setMaximum(KERNEL_MAX_VALUE);
    ui->horizontalSlider_GaussianBlur->setValue(m_kernelValueGaussianBlur);

    ui->horizontalSlider_FilterAll->setMinimum(KERNEL_MIN_VALUE);
    ui->horizontalSlider_FilterAll->setMaximum(KERNEL_MAX_VALUE);
    ui->horizontalSlider_FilterAll->setValue(m_kernelAll);

    ui->label_Kernel_BoxFilter->setText(QString::number(m_kernelValueBoxFilter));
    ui->label_Kernel_Blur->setText(QString::number(m_kernelValueBlur));
    ui->label_Kernel_GuassianBlur->setText(QString::number(m_kernelValueGaussianBlur));
    ui->label_Kernel_All->setText(QString::number(m_kernelAll));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,tr("Open Image"),".",tr("Image File(*.png *.jpg *.jpeg *.bmp)"));
    if (fileName.isEmpty())
    {
        return;
    }

    m_srcImage = imread(fileName.toLatin1().data());//读取图片数据
    if (!m_srcImage.data)
    {
        m_isOpenFile = false;
        QMessageBox box(QMessageBox::Critical, "打开图像", "读取图像文件失败!请重新打开.");
        box.setStandardButtons(QMessageBox::Ok);
        box.setButtonText(QMessageBox::Ok, QString("确定"));
        box.exec();
        return;
    }
    m_isOpenFile = true;//修改打开标志

    on_BoxFilter();
    on_Blur();
    on_GaussianBlur();
}

void MainWindow::on_horizontalSlider_BoxFilter_valueChanged(int value)
{
    if (m_isOpenFile)
    {
        m_kernelValueBoxFilter = value;
        ui->label_Kernel_BoxFilter->setText(QString::number(m_kernelValueBoxFilter));
        on_BoxFilter();
    }
}

void MainWindow::on_horizontalSlider_Blur_valueChanged(int value)
{
    if (m_isOpenFile)
    {
        m_kernelValueBlur = value;
        ui->label_Kernel_Blur->setText(QString::number(m_kernelValueBlur));
        on_Blur();
    }
}

void MainWindow::on_horizontalSlider_GaussianBlur_valueChanged(int value)
{
    if (m_isOpenFile)
    {
        m_kernelValueGaussianBlur = value;
        ui->label_Kernel_GuassianBlur->setText(QString::number(m_kernelValueGaussianBlur));
        on_GaussianBlur();
    }
}

void MainWindow::on_horizontalSlider_FilterAll_valueChanged(int value)
{
    if (m_isOpenFile)
    {
        m_kernelAll = value;
        ui->label_Kernel_All->setText(QString::number(m_kernelAll));

        ui->horizontalSlider_BoxFilter->setValue(m_kernelAll);
        ui->horizontalSlider_Blur->setValue(m_kernelAll);
        ui->horizontalSlider_GaussianBlur->setValue(m_kernelAll);
    }
}

void MainWindow::on_BoxFilter()
{
    boxFilter(m_srcImage, m_dstImage_BoxFilter, -1, Size(m_kernelValueBoxFilter + 1, m_kernelValueBoxFilter + 1));
    cvtColor(m_dstImage_BoxFilter, m_dstImage_BoxFilter, COLOR_BGR2RGB);//图像格式转换
    QImage disImage = QImage((const unsigned char*)(m_dstImage_BoxFilter.data),m_dstImage_BoxFilter.cols,m_dstImage_BoxFilter.rows,QImage::Format_RGB888);
    ui->label_Display1->setPixmap(QPixmap::fromImage(disImage.scaled(ui->label_Display1->width(), ui->label_Display1->height(), Qt::KeepAspectRatio)));
}

void MainWindow::on_Blur()
{
    blur(m_srcImage, m_dstImage_Blur, Size(m_kernelValueBlur + 1, m_kernelValueBlur + 1), Point(-1, -1));
    cvtColor(m_dstImage_Blur, m_dstImage_Blur, COLOR_BGR2RGB);//图像格式转换
    QImage disImage = QImage((const unsigned char*)(m_dstImage_Blur.data),m_dstImage_Blur.cols,m_dstImage_Blur.rows,QImage::Format_RGB888);
    ui->label_Display2->setPixmap(QPixmap::fromImage(disImage.scaled(ui->label_Display2->width(), ui->label_Display2->height(), Qt::KeepAspectRatio)));
}

void MainWindow::on_GaussianBlur()
{
    GaussianBlur(m_srcImage, m_dstImage_GaussianBlur, Size(m_kernelValueGaussianBlur * 2 + 1, m_kernelValueGaussianBlur * 2 + 1), 0, 0);
    cvtColor(m_dstImage_GaussianBlur, m_dstImage_GaussianBlur, COLOR_BGR2RGB);//图像格式转换
    QImage disImage = QImage((const unsigned char*)(m_dstImage_GaussianBlur.data),m_dstImage_GaussianBlur.cols,m_dstImage_GaussianBlur.rows,QImage::Format_RGB888);
    ui->label_Display3->setPixmap(QPixmap::fromImage(disImage.scaled(ui->label_Display3->width(), ui->label_Display3->height(), Qt::KeepAspectRatio)));
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 

#include "opencv2/opencv.hpp"
using namespace cv;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_horizontalSlider_BoxFilter_valueChanged(int value);

    void on_horizontalSlider_Blur_valueChanged(int value);

    void on_horizontalSlider_GaussianBlur_valueChanged(int value);

    void on_horizontalSlider_FilterAll_valueChanged(int value);

private:
    Ui::MainWindow *ui;

    int m_kernelValueBoxFilter;
    int m_kernelValueBlur;
    int m_kernelValueGaussianBlur;
    int m_kernelAll;

    bool m_isOpenFile;

    Mat m_srcImage;
    Mat m_dstImage_BoxFilter;
    Mat m_dstImage_Blur;
    Mat m_dstImage_GaussianBlur;

public:
    void on_BoxFilter(void);
    void on_Blur(void);
    void on_GaussianBlur(void);
};

#endif // MAINWINDOW_H

pro文件

#-------------------------------------------------
#
# Project created by QtCreator 2019-07-12T14:41:02
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = OpenCV_Filter
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

CONFIG += c++11

SOURCES += \
        main.cpp \
        mainwindow.cpp

HEADERS += \
        mainwindow.h

FORMS += \
        mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
INCLUDEPATH += $$PWD/../opencv_qt/include\
             $$PWD/../opencv_qt/include/opencv\
              $$PWD/../opencv_qt/include/opencv2

unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_calib3d410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_core410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_dnn410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_features2d410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_flann410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_highgui410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_imgcodecs410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_imgproc410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_ml410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_objdetect410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_photo410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_stitching410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_video410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -llibopencv_videoio410
unix|win32: LIBS += -L$$PWD/../opencv_qt/bin/ -lopencv_ffmpeg410

实验中,调整的值是核的大小,也就是函数中的ksize.width以及ksize.height。最小值为0,故预先加一,高斯滤波的核大小需要为正奇数。

boxFilter(m_srcImage, m_dstImage_BoxFilter, -1, Size(m_kernelValueBoxFilter + 1, m_kernelValueBoxFilter + 1));

blur(m_srcImage, m_dstImage_Blur, Size(m_kernelValueBlur + 1, m_kernelValueBlur + 1), Point(-1, -1));

GaussianBlur(m_srcImage, m_dstImage_GaussianBlur, Size(m_kernelValueGaussianBlur * 2 + 1, m_kernelValueGaussianBlur * 2 + 1), 0, 0);

原理学习参考:https://www.jianshu.com/p/b453c0f24b29

你可能感兴趣的:(学习笔记)