参考教程:https://blog.csdn.net/qingyang8513/article/details/80413402
数学形态学是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论,其基本运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰度腐蚀和膨胀、灰度形态学梯度等。
腐蚀与膨胀主要功能:
1)消除噪声;
2)分割;
3)寻找图像中的明显极大值区域或极小值区域;
4)求图像梯度;
膨胀就是求局部最大值的操作,针对的是图像中的高亮部分。从数学角度,膨胀或者腐蚀均是将图像A与核B进行卷积运算。核可以是任意形状和大小,其拥有一个单独定义出来的参考点,称其为锚点。膨胀运算是将核B与图像A进行卷积运算,求出局部最大值,并幅值给锚点。直观地,膨胀处理的结果是使图像的高亮部分区域增加。
腐蚀与膨胀的原理相同,均是采用图像A与核B进行卷积运算,不同的是腐蚀是求局部最小值的过程,运算结果是使图像高亮部分区域减少,或者可以说是图像较暗的区域增加。
实现方法:
①定义一个卷积核B,核可以是任何的形状和大小,且拥有一个单独定义出来的参考点 - 锚点(anchorpoint);
通常和为带参考点的正方形或者圆盘,可将核称为模板或掩膜;
②将核B与图像A进行卷积,计算核B覆盖区域的像素点最大值;
③将这个最大值赋值给参考点指定的像素;
因此,图像中的高亮区域逐渐增长。
实现方法:
①定义一个卷积核B,核可以是任何的形状和大小,且拥有一个单独定义出来的参考点 - 锚点(anchorpoint);
通常和为带参考点的正方形或者圆盘,可将核称为模板或掩膜;
②将核B与图像A进行卷积,计算核B覆盖区域的像素点最小值;
③将这个最小值赋值给参考点指定的像素;
因此,图像中的高亮区域逐渐减小。
原文:https://blog.csdn.net/qq_39861376/article/details/82111292
void cv::dilate | ( | InputArray | src, |
OutputArray | dst, | ||
InputArray | kernel, | ||
Point | anchor = Point(-1,-1) , |
||
int | iterations = 1 , |
||
int | borderType = BORDER_CONSTANT , |
||
const Scalar & | borderValue = morphologyDefaultBorderValue() |
||
) |
#include
通过使用特定的结构元素来扩展图像。
该函数使用指定的结构元素扩展源图像,该结构元素确定采用最大值的像素邻域的形状:
该功能支持就地模式。扩张可以应用几次(迭代)次。在多通道图像的情况下,每个通道被独立处理。
参数
SRC | 输入图像; 通道数可以是任意的,但深度应该是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。 |
DST | 输出与src相同大小和类型的图像。 |
核心 | 结构元素用于扩张; 如果elemenat = Mat(),则使用3 x 3矩形结构元素。可以使用getStructuringElement创建内核 |
锚 | 锚点在元素内的位置; 默认值(-1,-1)表示锚点位于元素中心。 |
迭代 | 应用扩张的次数。 |
borderType | 像素外推法,参见BorderTypes |
borderValue | 边界不变的边界值 |
void cv::erode | ( | InputArray | src, |
OutputArray | dst, | ||
InputArray | kernel, | ||
Point | anchor = Point(-1,-1) , |
||
int | iterations = 1 , |
||
int | borderType = BORDER_CONSTANT , |
||
const Scalar & | borderValue = morphologyDefaultBorderValue() |
||
) |
#include
使用特定的结构元素侵蚀图像。
该函数使用指定的结构元素侵蚀源图像,该结构元素确定采用最小值的像素邻域的形状:
该功能支持就地模式。侵蚀可以应用几次(迭代)次。在多通道图像的情况下,每个通道被独立处理。
参数
SRC | 输入图像; 通道数可以是任意的,但深度应该是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。 |
DST | 输出与src相同大小和类型的图像。 |
核心 | 用于侵蚀的结构元素; if element=Mat() ,使用3 x 3 矩形结构元素。可以使用getStructuringElement创建内核。 |
锚 | 锚点在元素内的位置; 默认值(-1,-1)表示锚点位于元素中心。 |
迭代 | 腐蚀的次数。 |
borderType | 像素外推法,参见BorderTypes |
borderValue | 边界不变的边界值 |
mainwindow.ui
MainWindow
0
0
655
416
MainWindow
30
20
54
12
原始图像:
360
20
54
12
运行效果:
30
70
261
191
border:1px solid black
Original Image
360
70
261
191
border:1px solid black
Processed Image
30
320
54
12
核大小:
120
320
21
20
background-color: rgb(255, 85, 127);
Qt::AlignCenter
160
320
221
20
Qt::Horizontal
550
320
75
23
打开图像
468
321
71
21
400
320
61
16
操作类型:
0
0
655
23
TopToolBarArea
false
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:
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
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#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();
}
}
}
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
演示结果:
可以看到膨胀就是让企鹅图像中白色(高亮)部分增多,腐蚀让企鹅黑色(暗色)部分增多。