前言
基于opencv的c++接口,实现常用的形态学处理方法,包括了腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算以及黑帽运算。
相关的opencv接口解析
CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
该函数用于构造并返回可以进一步传递给#erode、#dilate 或#morphologyEx 的结构元素。 但是您也可以自己构建任意二进制掩码并将其用作结构元素。
@param shape 可能是#MorphShapes 之一的元素形状
@param ksize 结构元素的大小。
@param anchor 元素内的锚点位置。 默认值 \fKaTeX parse error: Undefined control sequence: \f at position 9: (-1, -1)\̲f̲ 表示锚点位于中心。 请注意,只有十字形元素的形状取决于锚点位置。 在其他情况下,anchor 只是调节形态操作的结果移动了多少。
//! shape of the structuring element
enum MorphShapes {
MORPH_RECT = 0, //!< a rectangular structuring element: \f[E_{ij}=1\f]
MORPH_CROSS = 1, //!< a cross-shaped structuring element:
//!< \f[E_{ij} = \begin{cases} 1 & \texttt{if } {i=\texttt{anchor.y } {or } {j=\texttt{anchor.x}}} \\0 & \texttt{otherwise} \end{cases}\f]
MORPH_ELLIPSE = 2 //!< an elliptic structuring element, that is, a filled ellipse inscribed
//!< into the rectangle Rect(0, 0, esize.width, 0.esize.height)
};
CV_EXPORTS_W 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 输入图像;通道数可以是任意的,但深度应该是 CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F 之一。
@param dst 输出与 src 大小和类型相同的图像。
@param kernel 用于腐蚀的内核结构元素;如果 element=Mat(),则使用 3 x 3矩形结构元素。可以使用#getStructuringElement 创建内核。
@param anchor 在元素内的位置;默认值 (-1, -1) 表示锚点位于元素中心。
@param iterations 应用侵蚀的次数。
@param borderType 像素外推方法,参见#BorderTypes。不支持#BORDER_WRAP。
@param borderValue 边界值不变的情况下。
CV_EXPORTS_W 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 输入图像;通道数可以是任意的,但深度应该是 CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F 之一。
@param dst 输出与 src 大小和类型相同的图像。
@param kernel 用于膨胀的内核结构元素;如果 elemenat=Mat(),则使用 3 x 3 矩形结构元素。可以使用#getStructuringElement 创建内核
@param anchor 在元素内的位置;默认值 (-1, -1) 表示锚点位于元素中心。
@param iterations 应用膨胀的次数。
@param borderType 像素外推方法,参见#BorderTypes。不支持#BORDER_WRAP。
@param borderValue 边界值不变的情况下
CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst,
int op, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
函数 cv::morphologyEx 可以使用腐蚀和膨胀作为基本操作来执行高级形态变换。任何操作都可以就地完成。 在多通道图像的情况下,每个通道都是独立处理的。
@param src 源图像。 通道的数量可以是任意的。 深度应该是 CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F 之一。
@param dst 与源图像大小和类型相同的目标图像。
@param op 形态学操作的类型,参见#MorphTypes
@param kernel 结构元素。 它可以使用#getStructuringElement 创建。
@param anchor 与内核锚定位置。 负值表示锚点位于内核中心。
@param iterations 应用腐蚀和膨胀的次数。
@param borderType 像素外推法,见#BorderTypes。 不支持#BORDER_WRAP。
@param borderValue 边界值在恒定边界的情况下。 默认值具有特殊含义。
//! type of morphological operation
enum MorphTypes{
MORPH_ERODE = 0, //!< see #erode
MORPH_DILATE = 1, //!< see #dilate
MORPH_OPEN = 2, //!< an opening operation
//!< \f[\texttt{dst} = \mathrm{open} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \mathrm{erode} ( \texttt{src} , \texttt{element} ))\f]
MORPH_CLOSE = 3, //!< a closing operation
//!< \f[\texttt{dst} = \mathrm{close} ( \texttt{src} , \texttt{element} )= \mathrm{erode} ( \mathrm{dilate} ( \texttt{src} , \texttt{element} ))\f]
MORPH_GRADIENT = 4, //!< a morphological gradient
//!< \f[\texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} )\f]
MORPH_TOPHAT = 5, //!< "top hat"
//!< \f[\texttt{dst} = \mathrm{tophat} ( \texttt{src} , \texttt{element} )= \texttt{src} - \mathrm{open} ( \texttt{src} , \texttt{element} )\f]
MORPH_BLACKHAT = 6, //!< "black hat"
//!< \f[\texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src}\f]
MORPH_HITMISS = 7 //!< "hit or miss"
//!< .- Only supported for CV_8UC1 binary images. A tutorial can be found in the documentation
};
示例代码
morphological.h
#pragma once
#include <iostream>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
#define PROCESS_IMG_SUCESS 0
#define PROCESS_IMG_FAIL 1
namespace ImgEnhance
{
//形态学处理
class MorphologicalProcess
{
public:
MorphologicalProcess() {
cout << "MorphologicalProcess is being created" << endl; } // 这是构造函数声明
~MorphologicalProcess() {
cout << "MorphologicalProcess is being deleted" << endl; } // 这是析构函数声明
int ErodeProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize);//腐蚀
int DilateProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize);//膨胀
int OpenProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize);//开运算
int CloseProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize);//闭运算
int GradientProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize);//梯度运算(计算膨胀与腐蚀之间算术差;或膨胀结果与原图算术差;或原图与腐蚀结果算术差)
int TopHatProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize);//顶帽运算(计算原图与开运算之间算术差)
int BlackHatProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize);//黑帽运算(计算闭运算与原图之间算术差)
};
}
morphological.cpp
#include"morphological.h"
int ImgEnhance::MorphologicalProcess::ErodeProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(elementSize, elementSize));
// 腐蚀操作
cv::erode(srcImage, dstImage, element);
return 0;
}
int ImgEnhance::MorphologicalProcess::DilateProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(elementSize, elementSize));
// 膨胀操作
cv::dilate(srcImage, dstImage, element);
return 0;
}
int ImgEnhance::MorphologicalProcess::OpenProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(elementSize, elementSize));
// 形态学开操作
cv::morphologyEx(srcImage, dstImage, cv::MORPH_OPEN, element);
return 0;
}
int ImgEnhance::MorphologicalProcess::CloseProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(elementSize, elementSize));
// 形态学闭操作
cv::morphologyEx(srcImage, dstImage, cv::MORPH_CLOSE, element);
return 0;
}
int ImgEnhance::MorphologicalProcess::GradientProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(elementSize, elementSize));
// 形态学梯度
cv::morphologyEx(srcImage, dstImage, cv::MORPH_GRADIENT, element);
return 0;
}
int ImgEnhance::MorphologicalProcess::TopHatProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(elementSize, elementSize));
// 形态学Top-Hat 顶帽
cv::morphologyEx(srcImage, dstImage, cv::MORPH_TOPHAT, element);
return 0;
}
int ImgEnhance::MorphologicalProcess::BlackHatProcess(cv::Mat srcImage, cv::Mat &dstImage, int elementSize)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(elementSize, elementSize));
// 形态学Black-Hat 黑帽
cv::morphologyEx(srcImage, dstImage, cv::MORPH_BLACKHAT, element);
return 0;
}
test.cpp
#include"morphological.h"
ImgEnhance::MorphologicalProcess ImgM;//形态学处理
int main()
{
// 读取源图像及判断
cv::Mat srcImage = cv::imread("circle.jpg");
if (!srcImage.data)
{
return 1;
}
/*cv::namedWindow("原始图", 0);
cv::imshow("原始图", srcImage);*/
// 转化为灰度图像
cv::Mat srcGray;
if (srcImage.channels() == 3)
{
cv::cvtColor(srcImage, srcGray, COLOR_RGB2GRAY);
}
else
{
srcGray = srcImage.clone();
}
cv::namedWindow("灰度图", 0);
cv::imshow("灰度图", srcGray);
// 分通道二值化
Mat segDst;
cv::inRange(srcGray, cv::Scalar(0, 0, 100), cv::Scalar(40, 30, 255), segDst);
Mat erodeImage;
腐蚀
ImgM.ErodeProcess(segDst, erodeImage, 5);
cv::namedWindow("腐蚀结果图", 0);
cv::imshow("腐蚀结果图", erodeImage);
Mat dialateImage;
膨胀
ImgM.DilateProcess(segDst, dialateImage, 5);
cv::namedWindow("膨胀结果图", 0);
cv::imshow("膨胀结果图", dialateImage);
Mat openImage;
开运算
ImgM.OpenProcess(segDst, openImage, 5);
cv::namedWindow("开运算结果图", 0);
cv::imshow("开运算结果图", openImage);
Mat closeImage;
闭运算
ImgM.CloseProcess(segDst, closeImage, 5);
cv::namedWindow("闭运算结果图", 0);
cv::imshow("闭运算结果图", closeImage);
Mat gradientImage;
梯度运算
ImgM.GradientProcess(srcGray, gradientImage, 3);
cv::namedWindow("梯度运算结果图", 0);
cv::imshow("梯度运算结果图", gradientImage);
Mat tophatImage;
顶帽运算
ImgM.TopHatProcess(srcGray, tophatImage, 15);
cv::namedWindow("顶帽运算结果图", 0);
cv::imshow("顶帽运算结果图", tophatImage);
Mat blockhatImage;
黑帽运算
ImgM.BlackHatProcess(srcGray, blockhatImage, 15);
cv::namedWindow("黑帽运算结果图", 0);
cv::imshow("黑帽运算结果图", blockhatImage);
cv::waitKey(0);
return 0;
}