一、开发环境
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所示。
图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 运行效果
图2 膨胀效果1
图3 膨胀效果2
图4 腐蚀效果1
图5 腐蚀效果2