一. 图像形态学处理 —— 膨胀和腐蚀

腐蚀在二值图像的基础上做“收缩”或“细化”操作;

膨胀在二值图像的基础上做“加长”或“变粗”的操作。

ITK 形态学中的开运算和闭运算 腐蚀 膨胀_实例化

 

什么是二值图像呢?把一幅图片看做成一个二维的数组,那么二值图像是一个只有0和1的逻辑数组,我们前面Sobel边缘检测后的图像输出边缘效果,设置个阈值,大于阈值输出为1,小于阈值输出为0,最后输出就是一幅二值图像了。

腐蚀

腐蚀是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的物体。用3X3的结构元素,扫描图像的每一个像素,用结构元素与其覆盖的二值图像做“与”操作,如果都为1,结果图像的该像素为1。否则为0。结果会使二值图像小一圈。

有一个形象的比喻来可以说明该运算,用0表示蛀虫,1表示大米。蛀虫腐蚀大米的过程便是

ITK 形态学中的开运算和闭运算 腐蚀 膨胀_ITK_02

 

 如图所示,对于一个像素矩阵而言,只要有蛀虫(0)的存在,大米(1)就会被腐蚀掉了,即使只存在一个蛀虫(0),但是还是会被蛀虫腐蚀完毕,最后一幅图上面由于没有蛀虫(0)所以大米完好无损。

膨胀

膨胀是将与物体接触的所有背景点合并到该物体中,使边界向外部扩张的过程。可以用来填补物体中的空洞。用3X3的结构元素,扫描图像的每一个像素,用结构元素与其覆盖的二值图像做“与”操作,如果都为0,结果图像的该像素为0,。否则为1。结果使二值图像扩大一圈。

先腐蚀后膨胀的过程称为开运算。用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显的改变其面积。先膨胀后腐蚀的过程称为比运算,用来填充物体内细小空间、连接邻近物体、平滑其边界的同时并不明显改变其面积。

膨胀算法用最简单的比喻来描述:0表示害虫,1表示青蛙,青蛙吃了害虫表示膨胀运算,我们用3*3像素阵列来解释:

ITK 形态学中的开运算和闭运算 腐蚀 膨胀_#include_03

 

 

膨胀

如图所示,图左只有害虫(0),所以害虫都活着,中间那个图,虽然只有一个害虫,但是还是会被青蛙全部吃掉,最右边的那幅图,都是青蛙,所以青蛙始终是青蛙。

二. 开运算与闭运算:

    开运算:先腐蚀后膨胀,能够消除图像区域外的小白点(噪声)。

    闭运算:先膨胀后腐蚀,能够消除图像区域内的小黑点(噪声)。

ITK 形态学中的开运算和闭运算 腐蚀 膨胀_二值图像_04

 腐蚀:

//ITK
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
//#include "itkBinaryErodeImageFilter.h"//这是二值图像的腐蚀
#include "itkGrayscaleErodeImageFilter.h"
#include "itkBinaryBallStructuringElement.h"
#include "itkBinaryThresholdImageFilter.h"
//C++
#include "iostream"
using namespace std;
int main() {
// 实例化对象模型
const unsigned int Dimension = 2;
typedef unsigned char InputPixelType;
typedef unsigned char OutputPixelType;
typedef itk::Image< InputPixelType, Dimension > InputImageType;
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
typedef itk::ImageFileReader< InputImageType > ReaderType;
typedef itk::ImageFileWriter< OutputImageType > WriterType;

//用于二值图像的构造成员
typedef itk::BinaryBallStructuringElement< InputPixelType, Dimension > StructuringElementType;
// 腐蚀,需要用输入、输出图像类型和构造成员实例化¯
typedef itk::GrayscaleErodeImageFilter <
InputImageType,
OutputImageType,
StructuringElementType > ErodeFilterType;
// 读取、写入图像文件滤波器
ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName("../data/threshold.png");

// /*创建腐蚀滤波器对象
// 创建构造成员对象
StructuringElementType structuringElement;
structuringElement.SetRadius(3); //领域大小为3*3,结构元素se为3*3
structuringElement.CreateStructuringElement();
//
ErodeFilterType::Pointer GrayscaleErode = ErodeFilterType::New();
GrayscaleErode->SetInput(reader->GetOutput());
GrayscaleErode->SetKernel(structuringElement);

// 触发腐蚀处理后的写操作
WriterType::Pointer writerErosion = WriterType::New();
writerErosion->SetFileName("../save/Erosion.png");
writerErosion->SetInput(GrayscaleErode->GetOutput());
writerErosion->Update();
return EXIT_SUCCESS;
}

膨胀

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkBinaryErodeImageFilter.h"
#include "itkBinaryDilateImageFilter.h"
#include "itkBinaryBallStructuringElement.h"
#include "itkBinaryThresholdImageFilter.h"
int main() {
// 实例化对象模型
const unsigned int Dimension = 2;
typedef unsigned char InputPixelType;
typedef unsigned char OutputPixelType;
typedef itk::Image< InputPixelType, Dimension > InputImageType;
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
//
typedef itk::ImageFileReader< InputImageType > ReaderType;
// 读取、写入图像文件滤波器
ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName("../data/threshold.png");

//用于二值图像的构造成员
typedef itk::BinaryBallStructuringElement< InputPixelType, Dimension > StructuringElementType;
StructuringElementType structuringElement;
structuringElement.SetRadius(1); //领域大小为3*3
structuringElement.CreateStructuringElement();

// 腐蚀,需要用输入、输出图像类型和构造成员实例化
typedef itk::BinaryErodeImageFilter <
InputImageType,
OutputImageType,
StructuringElementType > ErodeFilterType;
// 膨胀,需要用输入、输出图像类型和构造成员实例化
typedef itk::BinaryDilateImageFilter <
InputImageType,
OutputImageType,
StructuringElementType > DilateFilterType;

// 创建腐蚀和膨胀滤波器对象
ErodeFilterType::Pointer binaryErode = ErodeFilterType::New();
binaryErode->SetInput(reader->GetOutput());
binaryErode->SetKernel(structuringElement);
binaryErode->SetErodeValue(255);
binaryErode->Update();
//
DilateFilterType::Pointer binaryDilate = DilateFilterType::New();
binaryDilate->SetInput(reader->GetOutput());
binaryDilate->SetKernel(structuringElement);
binaryDilate->SetDilateValue(255);
binaryDilate->Update();
typedef itk::ImageFileWriter< OutputImageType > WriterType;
WriterType::Pointer writerErosion = WriterType::New();
writerErosion->SetFileName("../save/1Erosion.png");
writerErosion->SetInput(binaryErode->GetOutput());
writerErosion->Update();
WriterType::Pointer writerDilation = WriterType::New();
writerDilation->SetFileName("../save/1Dilation.png");
writerDilation->SetInput(binaryDilate->GetOutput());
writerDilation->Update();

return EXIT_SUCCESS;
}