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

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

非线型滤波
    线型滤波易于构造,易于从频率响应角度分析,但是,很多情况下,如果脉冲噪声、椒盐噪声明显时,或者需要较好的保存边缘时,线型滤波往往无法达到需要的效果,此时就需要用到非线性滤波。

    常见的非线性滤波有:中值滤波、双边滤波

    中值滤波基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声的同时又能保存图像的边缘细节。和均值滤波相比,中值滤波可以有效滤除高频噪声的同时保存边缘,但其由于运算过程中需要进行排序,因此运行时间约是均值滤波的5倍以上。中值滤波邻域大小一般采用奇数点来运算。

    双边滤波是基于空间分布高斯滤波函数,比高斯滤波多一个高斯方差sigma-d,在边缘附近,离得远的像素不会对边缘上的像素影响太多,可以很好的做边缘保存。

3.1 中值滤波

OpenCV函数原型及参数说明:

medianBlur()

void cv::medianBlur(InputArray src,
  OutputArray dst,
  int ksize 
 )  

 

#include <opencv2/imgproc.hpp>

使用中值滤波器模糊图像。

该函数使用具有ksize×ksize的中值滤波器来平滑图像光圈。多通道图像的每个通道都是独立处理的。支持就地操作。

参数

SRC输入1,3-或4通道图像; 当ksize为3或5时,图像深度应为CV_8U,CV_16U或CV_32F,对于较大的光圈尺寸,它只能是CV_8U。
DST与src具有相同大小和类型的目标数组。
ksize孔径线性尺寸; 它必须是奇数且大于1,例如:3,5,7 ......

https://docs.opencv.org/4.1.0/d4/d86/group__imgproc__filter.html#ga564869aa33e58769b4469101aac458f9

3.2 双边滤波

OpenCV函数原型及参数说明:

bilateralFilter()

void cv::bilateralFilter(InputArray src,
  OutputArray dst,
  int d,
  double sigmaColor,
  double sigmaSpace,
  int borderType = BORDER_DEFAULT 
 )  

 

#include <opencv2/imgproc.hpp>

将双边滤波器应用于图像。

该函数对输入图像应用双边过滤,如http://www.dai.e.ac.uk/cvonline/local_copies/manduchi1/bilateral_filtering.html所述,双边过滤可以很好地减少不必要的噪声,同时保持边缘相当清晰。然而,与大多数过滤器相比,它非常慢。

西格玛值:为了简单起见,您可以将2西格玛值设置为相同的值。如果它们很小(< 10),过滤器将不会有太大的效果,而如果它们很大(> 150),它们将有非常强的效果,使图像看起来“卡通化”。

过滤器大小:大型过滤器(d > 5)非常慢,因此建议对实时应用程序使用d=5,对于需要进行重噪声过滤的离线应用程序可能使用d=9。

这个过滤器不支持就地工作。

参数

Parameters

src源8位或浮点数,1通道或3通道图像
dst与src大小和类型相同的目标映像
d用于滤波的每个像素邻域的直径。如果它是非正数,则从sigmaSpace计算。
sigmaColorF在颜色空间中过滤。较大的参数值意味着像素邻域内的较远颜色(参见sigmaSpace)将混合在一起,从而产生较大的半等色区域。
sigmaSpace在坐标空间中过滤。参数值越大,表示距离越远的像素只要颜色足够接近就会相互影响(参见sigmaColor)。当d>0时,它指定了与sigmaSpace无关的邻域大小。否则,d与sigmaSpace成正比。
borderType用于推断图像外部像素的边框模式,请参见BorderTypes

示例设计与测试

4.1 界面设计

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>979</width>
    <height>416</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>20</y>
      <width>54</width>
      <height>12</height>
     </rect>
    </property>
    <property name="text">
     <string>原始图像:</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_2">
    <property name="geometry">
     <rect>
      <x>360</x>
      <y>20</y>
      <width>54</width>
      <height>12</height>
     </rect>
    </property>
    <property name="text">
     <string>中值滤波:</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_OriginalImg">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>70</y>
      <width>261</width>
      <height>191</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">border:1px solid black</string>
    </property>
    <property name="text">
     <string>Original  Image</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_ProcessedImg">
    <property name="geometry">
     <rect>
      <x>360</x>
      <y>70</y>
      <width>261</width>
      <height>191</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">border:1px solid black</string>
    </property>
    <property name="text">
     <string>Processed  Image</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_5">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>320</y>
      <width>54</width>
      <height>12</height>
     </rect>
    </property>
    <property name="text">
     <string>邻域直径:</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_KernelValue">
    <property name="geometry">
     <rect>
      <x>120</x>
      <y>320</y>
      <width>21</width>
      <height>20</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color: rgb(255, 85, 127);</string>
    </property>
    <property name="text">
     <string/>
    </property>
    <property name="alignment">
     <set>Qt::AlignCenter</set>
    </property>
   </widget>
   <widget class="QSlider" name="horizontalSlider_DValue">
    <property name="geometry">
     <rect>
      <x>180</x>
      <y>320</y>
      <width>671</width>
      <height>19</height>
     </rect>
    </property>
    <property name="orientation">
     <enum>Qt::Horizontal</enum>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton_OpenImg">
    <property name="geometry">
     <rect>
      <x>880</x>
      <y>320</y>
      <width>75</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>打开图像</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_ProcessedImg2">
    <property name="geometry">
     <rect>
      <x>690</x>
      <y>70</y>
      <width>261</width>
      <height>191</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">border:1px solid black</string>
    </property>
    <property name="text">
     <string>Processed  Image2</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_3">
    <property name="geometry">
     <rect>
      <x>690</x>
      <y>20</y>
      <width>54</width>
      <height>12</height>
     </rect>
    </property>
    <property name="text">
     <string>双边滤波:</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>979</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QMessageBox>

#define KERNEL_MIN_VALUE    0
#define KERNEL_MAX_VALUE    40

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle(tr("Qt_OpenCV线型滤波"));

    //初始化变量
    m_KernelValue = 3;
    m_isOpenFile = false;

    //初始化控件
    ui->horizontalSlider_DValue->setMinimum(KERNEL_MIN_VALUE);
    ui->horizontalSlider_DValue->setMaximum(KERNEL_MAX_VALUE);
    ui->horizontalSlider_DValue->setValue(m_KernelValue);
    ui->label_KernelValue->setText(QString::number(m_KernelValue));
}

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

void MainWindow::on_pushButton_OpenImg_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;//修改打开标志

    Mat disImageTemp;
    cvtColor(m_srcImage, disImageTemp, COLOR_BGR2RGB);//图像格式转换
    QImage disImage = QImage((const unsigned char*)(disImageTemp.data),disImageTemp.cols,disImageTemp.rows,QImage::Format_RGB888);
    ui->label_OriginalImg->setPixmap(QPixmap::fromImage(disImage.scaled(ui->label_OriginalImg->width(), ui->label_OriginalImg->height(), Qt::KeepAspectRatio)));

    on_MedianBlur();
    on_BilateralFilter();
}

void MainWindow::on_horizontalSlider_DValue_valueChanged(int value)
{
    if (m_isOpenFile)
    {
        m_KernelValue = value;
        ui->label_KernelValue->setText(QString::number(m_KernelValue));
        on_MedianBlur();
        on_BilateralFilter();
    }
}

void MainWindow::on_MedianBlur()
{
    medianBlur(m_srcImage, m_dstImage, m_KernelValue * 2 + 1);//中值滤波
    cvtColor(m_dstImage, m_dstImage, COLOR_BGR2RGB);//图像格式转换
    QImage disImage = QImage((const unsigned char*)(m_dstImage.data),m_dstImage.cols,m_dstImage.rows,QImage::Format_RGB888);
    ui->label_ProcessedImg->setPixmap(QPixmap::fromImage(disImage.scaled(ui->label_ProcessedImg->width(), ui->label_ProcessedImg->height(), Qt::KeepAspectRatio)));
}


void MainWindow::on_BilateralFilter()
{
    bilateralFilter(m_srcImage, m_dstImage, m_KernelValue, m_KernelValue * 2, m_KernelValue / 2);//双边滤波
    cvtColor(m_dstImage, m_dstImage, COLOR_BGR2RGB);//图像格式转换
    QImage disImage = QImage((const unsigned char*)(m_dstImage.data),m_dstImage.cols,m_dstImage.rows,QImage::Format_RGB888);
    ui->label_ProcessedImg2->setPixmap(QPixmap::fromImage(disImage.scaled(ui->label_ProcessedImg2->width(), ui->label_ProcessedImg2->height(), Qt::KeepAspectRatio)));
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#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:
    Ui::MainWindow *ui;

    int m_KernelValue;
    bool m_isOpenFile;

    Mat m_srcImage;
    Mat m_dstImage;

public:
    void on_MedianBlur(void);
    void on_BilateralFilter(void);
private slots:
    void on_pushButton_OpenImg_clicked();
    void on_horizontalSlider_DValue_valueChanged(int value);
};

#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

效果:

可以看出,双边滤波与中值滤波相比能够更清晰地保留边缘,前者实际上就是先对图像做高斯模糊,再对模糊后的图像做边缘保持的操作。用时上,双边滤波更慢一些。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值