一、开发环境

1、Windows 7 64位 SP1 旗舰版;

2、Qt 5.10.1;

3、OpenCV 3.4.1

二、形态学腐蚀与膨胀

    数学形态学是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论,其基本运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰度腐蚀和膨胀、灰度形态学梯度等。

    腐蚀与膨胀主要功能:

    1)消除噪声;

    2)分割;

    3)寻找图像中的明显极大值区域或极小值区域;

    4)求图像梯度;

    膨胀就是求局部最大值的操作,针对的是图像中的高亮部分。从数学角度,膨胀或者腐蚀均是将图像A与核B进行卷积运算。核可以是任意形状和大小,其拥有一个单独定义出来的参考点,称其为锚点。膨胀运算是将核B与图像A进行卷积运算,求出局部最大值,并幅值给锚点。直观地,膨胀处理的结果是使图像的高亮部分区域增加。

    腐蚀与膨胀的原理相同,均是采用图像A与核B进行卷积运算,不同的是腐蚀是求局部最小值的过程,运算结果是使图像高亮部分区域减少,或者可以说是图像较暗的区域增加。

三、OpenCV实现

1、膨胀函数原型:

void dilate( InputArray src, OutputArray dst, InputArray kernel,
                          Point anchor = Point(-1,-1), int iterations = 1,
                          int borderType = BORDER_CONSTANT,
                          const Scalar& borderValue = morphologyDefaultBorderValue() );
@param src input image; the number of channels can be arbitrary, but the depth should be one of
	   CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src\`.
@param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular
       structuring element is used. Kernel can be created using getStructuringElement
@param anchor position of the anchor within the element; default value (-1, -1) means that the
       anchor is at the element center.
@param iterations number of times dilation is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border


2、腐蚀函数原型:

void erode( InputArray src, OutputArray dst, InputArray kernel,
                         Point anchor = Point(-1,-1), int iterations = 1,
                         int borderType = BORDER_CONSTANT,
                         const Scalar& borderValue = morphologyDefaultBorderValue() );
@param src input image; the number of channels can be arbitrary, but the depth should be one of
	   CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src.
@param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular
       structuring element is used. Kernel can be created using getStructuringElement.
@param anchor position of the anchor within the element; default value (-1, -1) means that the
       anchor is at the element center.
@param iterations number of times erosion is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border


四、示例设计与测试
4.1 界面设计

    界面设计如图1所示。

opencv图像膨胀源码_sed

图1 界面设计

4.2 程序源码

1、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;
    int m_typeCurSel;

    Mat m_srcImage;
    Mat m_dstImage;

public:
    void on_Dilate(void);
    void on_Erode(void);
private slots:
    void on_pushButton_OpenImg_clicked();
    void on_comboBox_Type_currentIndexChanged(int index);
    void on_horizontalSlider_KernelValue_valueChanged(int value);
};

#endif // MAINWINDOW_H

2、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 = 1;
    m_isOpenFile = false;
    m_typeCurSel = 0;

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

    ui->comboBox_Type->insertItem(0, "膨胀");
    ui->comboBox_Type->insertItem(1, "腐蚀");
    ui->comboBox_Type->setCurrentIndex(m_typeCurSel);
}

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)));

    if (m_typeCurSel == 0)
    {
        on_Dilate();
    }
    else
    {
        on_Erode();
    }
}

void MainWindow::on_horizontalSlider_KernelValue_valueChanged(int value)
{
    if (m_isOpenFile)
    {
        m_KernelValue = value;
        ui->label_KernelValue->setText(QString::number(m_KernelValue));
        if (m_typeCurSel == 0)
        {
            on_Dilate();
        }
        else
        {
            on_Erode();
        }
    }
}

void MainWindow::on_Dilate()
{
    //获取内核形状和尺寸
    Mat element = getStructuringElement(MORPH_RECT, Size(m_KernelValue * 2 + 1, m_KernelValue * 2 + 1), Point(m_KernelValue, m_KernelValue));

    //膨胀操作
    dilate(m_srcImage, m_dstImage, element);

    //显示
    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_Erode()
{
    //获取内核形状和尺寸
    Mat element = getStructuringElement(MORPH_RECT, Size(m_KernelValue * 2 + 1, m_KernelValue * 2 + 1), Point(m_KernelValue, m_KernelValue));

    //腐蚀操作
    erode(m_srcImage, m_dstImage, element);

    //显示
    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_comboBox_Type_currentIndexChanged(int index)
{
    m_typeCurSel = index;
    if (m_isOpenFile)
    {
        if (m_typeCurSel == 0)
        {
            on_Dilate();
        }
        else
        {
            on_Erode();
        }
    }
}



4.3 运行效果


opencv图像膨胀源码_opencv图像膨胀源码_02

图2 膨胀效果1

opencv图像膨胀源码_sed_03

图3 膨胀效果2

opencv图像膨胀源码_OpenCV_04

图4 腐蚀效果1

opencv图像膨胀源码_opencv图像膨胀源码_05

图5 腐蚀效果2