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() )
op:
MORPH_OPEN 开运算
MORPH_CLOSE 闭运算
MORPH_GRADIENT 形态学梯度
MORPH_TOPHAT 顶帽
MORPH_BLACKHAT 黑帽
MORPH_ERODE 腐蚀
MORPH_DILATE 膨胀
kernel形态运算的内核,一般由getStructuringElement函数生成,有三种形状
MORPH_RECT 矩形
MORPH_CROSS 交叉形
MORPH_ELLIPSE 椭圆形
是形态学的基本操作,在灰度图像中也是如此,在二值图像中腐蚀和膨胀定义为对图像进行translation以后的“与”和“或”的逻辑操作结果,在灰度图像中,为了保存灰度信息,“与”和“或”操作被对应的替换成了“最大值”和“最小值”操作这样就给出了灰度图像中腐蚀和膨胀的操作定义。
桥接断裂,修复断裂的结构元
void dilate( InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue());
将小于结构元的图像细节从图像中去除
void erode( InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
先腐蚀后膨胀的过程。可以用来消除黑色背景中的白色斑点(背景中的白点),在纤细点处分离物体,并且平滑物体的轮廓、断开较窄的狭颈
morphologyEx( InputArray src, OutputArray dst,MORPH_OPEN,element)
先膨胀后腐蚀,能够消除白色背景中的黑色斑点(前景中的黑点),一般会弥合较窄的尖端和细长的沟壑,消除小的孔洞,填补轮廓线的断裂。它有助于关闭前景物体内部的小孔,或物体上的小黑点。
morphologyEx( InputArray src, OutputArray dst,MORPH_CLOSE,element)
膨胀(image)-腐蚀(image),是膨胀图减去腐蚀图的差,将团块(blob)边缘凸显,用来保留物体的边缘轮廓。
可以计算的梯度常见如下四种:
基本梯度:
基本梯度是用膨胀后的图像减去腐蚀后的图像得到差值图像,称为梯度图像也是OpenCV中支持的计算形态学梯度的方法,而此方法得到梯度有被称为基本梯度。
内部梯度:
是用原图像减去腐蚀之后的图像得到差值图像,称为图像的内部梯度。
外部梯度:
是用图像膨胀之后再减去原来的图像得到的差值图像,称为图像的外部梯度。
方向梯度:
方向梯度是使用X方向与Y方向的直线作为结构元素之后得到图像梯度,用X方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为X方向梯度,用Y方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为Y方向梯度。
int main()
{
//首先读入图像,并二值化
cv::Mat srcImage = cv::imread("../pictures/000177.png",cv::IMREAD_GRAYSCALE);
cv::threshold(srcImage,srcImage,125,255,cv::THRESH_BINARY);
cv::imshow("srcImage",srcImage);
//获取进行形态学操作的核
cv::Mat elementRect;
elementRect = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3),cv::Point(-1,-1));
//膨胀
cv::Mat dilateImage;
cv::dilate(srcImage,dilateImage,elementRect);
//cv::morphologyEx(srcImage,dilateImage,cv::MORPH_DILATE,elementRect);
//腐蚀
cv::Mat erodeImage;
cv::erode(srcImage,erodeImage,elementRect);
//cv::morphologyEx(srcImage,dilateImage,cv::MORPH_ERODE,elementRect);
//1.计算基本梯度:膨胀后的图像减去腐蚀后的图像
cv::Mat basicGradient;
cv::subtract(dilateImage, erodeImage, basicGradient, cv::Mat());
//cv::morphologyEx(srcImage,basicGradient,cv::MORPH_GRADIENT,elementRect);//两者等效
cv::imshow("basicGradient", basicGradient);
//2.计算内部梯度:原图像减去腐蚀之后的图像
cv::Mat internalGradientImg;
cv::subtract(srcImage, erodeImage, internalGradientImg, cv::Mat());
cv::imshow("internalGradientImg", internalGradientImg);
//3.计算外部梯度:膨胀后的图像减去原图像
cv::Mat externalGradientImg;
cv::subtract(dilateImage, srcImage, externalGradientImg, cv::Mat());
cv::imshow("externalGradientImg", externalGradientImg);
//4.方向梯度:使用X方向与Y方向的直线作为结构元素---------
//cv::Mat hse = getStructuringElement(cv::MORPH_RECT, cv::Size(srcImage.cols / 16, 1),cv::Point(-1,-1));
//cv::Mat vse = getStructuringElement(cv::MORPH_RECT, cv::Size(1, srcImage.rows / 16),cv::Point(-1,-1));
cv::Mat hse = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 1),cv::Point(-1,-1));
cv::Mat vse = getStructuringElement(cv::MORPH_RECT, cv::Size(1, 3),cv::Point(-1,-1));
cv::Mat xDirectImg, yDirectImg;
//4.1 X 方向梯度:膨胀与腐蚀之后得到图像求差值
cv::erode(srcImage, erodeImage, hse);
cv::dilate(srcImage, dilateImage, hse);
cv::subtract(dilateImage, erodeImage, xDirectImg, cv::Mat());
cv::imshow("xDirectImg", xDirectImg);
//cv::imshow("dilateImage",dilateImage);
//cv::imshow("erodeImage",erodeImage);
//4.2 Y 方向梯度:膨胀与腐蚀之后得到图像求差值
cv::erode(srcImage, erodeImage, vse);
cv::dilate(srcImage, dilateImage, vse);
cv::subtract(dilateImage, erodeImage, yDirectImg, cv::Mat());
cv::imshow("yDirectImg", yDirectImg);
cv::waitKey(0);
return 0;
}
采用两个结构基元H,M,作为一个结构元素对B= (H, M) ,一个探测目标内部,一个探测目标外部。当且仅当H平移到某一点可填入X的内部, M平移到该点可填入A的外部时,该点才在击中击不中变换的输出中。则击中击不中变换为:用B1去腐蚀A,然后用B2去腐蚀A的补集,得到的结果相减就是击中击不中变换。
击中其实是一种模板匹配,如果一个结构元(模板)与图像中的一个连通区域完全相等,那么腐蚀的结果将是一个点,这就算是“击中”了,因为找到了完全一致的模式(模式的含义去查一下吧,这里的模式和模式识别的模式含义相同),但如果模板与联通区域去不完全相同,但腐蚀后的结果还是一个点,我们也称为一种“击中”,但不是严格的击中,比如我们的模板是一个直径为10的实心圆形,连通区域是一个直径为10的实心圆和一个直径为1的实心圆的并列排布,其腐蚀结果也是一个点,但其不是完美的击中,要找到完美的击中,必须在模板外面加个边框(或者是背景),这样的结果就不会出现不完美击中,我们可以选模板外一圈黑色的背景(红色背景)作为边框,与上述连通区域做击中操作,很明显。
应用:①物体识别:将击中基元设计成为需要识别的图像的样子,击不中基元设计为击中基元取反后的样子,然后用这两个基元对图像进行检测即可。②图像细化:将图像变细,就像取到了图像的骨架。
morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);
礼帽(image)=image-开运算(image),是原图减去“开运算”的结果图之差,突出了比原图轮廓周围区域更亮的区域,用来分离比邻近点亮一些的斑块。顶帽变换用于凸显暗背景上的亮物体。对二值图来说,进行顶帽变换或之后底帽变换看起来就像是加一个阴影,有一种立体的效果。
morphologyEx( InputArray src, OutputArray dst,MORPH_TOPHAT,element)
黑帽(image)=闭运算(image)-image,是闭运算的结果减去原图像之差,突出了比原图轮廓周围区域更暗的区域。黑帽运算用来分离比邻近点暗一些的斑块,黑帽变换可以用于凸显亮背景上的暗物体。二值图效果与顶帽变换相比,就是一个方向相反的阴影。
morphologyEx( InputArray src, OutputArray dst,MORPH_BLACKHAT,element)