OPENCV形态学操作1

形态学操作是指基于形状的一系列图像处理操作,包括膨胀,腐蚀,二值化,开运算,闭运算,顶帽算法,黑帽算法,形态学梯度等,最基本的形态学操作就是膨胀和腐蚀.

一.膨胀

首先需要明确一个概念,膨胀和腐蚀都是针对于图像中较亮的区域而言的,膨胀就是亮的区域变多了,而腐蚀就是暗的区域变多了.

膨胀的功能主要有消除噪声,分割出独立的图像元素,在图像操作的时候,有时候需要对图像中的某些形状进行检测,而这些形状相互连接在一起,不好分开检测,膨胀就能切开这些形状(很小的连接位置),或者图像中有很小块的黑斑,或许是相机上的影响,膨胀,也能消除这些小的黑斑

膨胀的基本思路就是图像与一个核函数进行卷积,并取出结果中的极大值作为结果,使得图像中的高亮区域增长.这个核的形状,锚点都可以进行设置,OPENCV提供了API供我们获得核.

API:Mat getStructuringElement(int 内核形状,Size 内核尺寸,Point 锚点位置)

注:内核形状可以取方形MORPH_RECT,十字形MORPH_CROSS,椭圆形MORPH_ELLIPSE

锚点位置默认值Point(-1,-1),取形状的中心

通过该API就可以获得相应的计算核,接下来计算膨胀的函数为

API:void dilate(源图像,目标图像,膨胀核,锚点,int 迭代次数,int边界模式,int 边界为常数时边界值)

注:该API支持in_place(源图像可以做目的图像参数,算法会修改源图像内数据),迭代次数默认为1

例子如下

Mat srcImage;
//膨胀
const int g_dilateIterMax = 100;//迭代次数
int g_nDilateIterValue;
const int g_dilateCoreMax = 100;//核大小
int g_nDilateCoreValue;
Mat dilateImage;
void OnDilateIterTrackbar(int pos,void* userData);
void onDilateCoreSizeTrackBar(int pos,void* userData);

int main(int argc,char* argv)
{
	srcImage = imread("F:\\opencv\\OpenCVImage\\erode_dilate.jpg");
	namedWindow("src image");
	namedWindow("dilate image");

	g_nDilateIterValue = 1;
	g_nDilateCoreValue = 5;
	createTrackbar("inter count", "dilate image", &g_nDilateIterValue, g_dilateIterMax,OnDilateIterTrackbar);
	createTrackbar("core size", "dilate image", &g_nDilateCoreValue, g_dilateCoreMax,onDilateCoreSizeTrackBar);
	OnDilateIterTrackbar(g_nDilateIterValue,0);

	moveWindow("src image", 0, 0);
	moveWindow("dilate image", srcImage.cols, 0);

	imshow("src image", srcImage);

	waitKey(0);
	return 0;
}

//调整迭代次数
void OnDilateIterTrackbar(int pos,void* userData)
{
   if(pos == 0||g_nDilateCoreValue == 0)
   {
       imshow("dilate image", srcImage);
   }
   else
   {
       if(g_nDilateCoreValue%2 == 0)
       {
           g_nDilateCoreValue++;
       }
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nDilateCoreValue,g_nDilateCoreValue));
       dilate(srcImage, dilateImage, core,Point(-1,-1),g_nDilateIterValue);
       imshow("dilate image", dilateImage);
   }
}

//调整核大小
void onDilateCoreSizeTrackBar(int pos,void* userData)
{
   if(pos == 0 || g_nDilateIterValue == 0)
   {
       imshow("dilate image", srcImage);
   }
   else
   {
       if(g_nDilateCoreValue%2 == 0)
       {
           g_nDilateCoreValue++;
       }
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nDilateCoreValue,g_nDilateCoreValue));
       dilate(srcImage, dilateImage, core,Point(-1,-1),g_nDilateIterValue);
       imshow("dilate image", dilateImage);
   }
}

  

二.腐蚀

腐蚀与膨胀正好相反,是求局部最小值的操作,亮的地方会减少,黑的地方会增多,在图像中连接接近的区域,消除高亮造成的噪声

API: void erode(源,目的,核,锚点,迭代次数,边缘类型,边缘为常数时边界值);

注:腐蚀和膨胀API的形式一致

使用代码

//腐蚀
Mat srcImage;
const int g_erodeIterMax = 100;
int g_nErodeIterValue;
const int g_erodeCoreMax = 100;
int g_nErodeCoreValue;
Mat erodeImage;
void OnErodeIterTrackbar(int pos,void* userData);
void onErodeCoreSizeTrackBar(int pos,void* userData);

int main(int argc,char* argv)

{
	srcImage = imread("F:\\opencv\\OpenCVImage\\erode_dilate.jpg");
	namedWindow("src image");
    namedWindow("erode image");

   g_nErodeIterValue = 1;
   g_nErodeCoreValue = 5;
   createTrackbar("inter count", "erode image", &g_nErodeIterValue, g_erodeIterMax,OnErodeIterTrackbar);
   createTrackbar("core size", "erode image", &g_nErodeCoreValue, g_erodeCoreMax,onErodeCoreSizeTrackBar);
   OnErodeIterTrackbar(g_nErodeIterValue, 0);

	moveWindow("src image", 0, 0);
    moveWindow("erode image", srcImage.cols, 0);

	imshow("src image", srcImage);
	waitKey(0);
	return 0;	

}

//调整迭代次数
void OnErodeIterTrackbar(int pos,void* userData)
{
   if(pos == 0 || g_nErodeCoreValue == 0)
   {
       imshow("erode image", srcImage);
   }
   else
   {
       if(g_nErodeCoreValue%2 == 0)
       {
           g_nErodeCoreValue++;
       }
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nErodeCoreValue,g_nErodeCoreValue),Point(-1,-1));
       erode(srcImage, erodeImage, core,Point(-1,-1),g_nErodeIterValue);
       imshow("erode image", erodeImage);
   }
}
//调整核大小
void onErodeCoreSizeTrackBar(int pos,void* userData)
{
   if(pos == 0 || g_nErodeIterValue == 0)
   {
       imshow("erode image", srcImage);
   }
   else
   {
       if(g_nErodeCoreValue%2 == 0)
       {
           g_nErodeCoreValue++;
       }
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nErodeCoreValue,g_nErodeCoreValue),Point(-1,-1));
       erode(srcImage, erodeImage, core,Point(-1,-1),g_nErodeIterValue);
       imshow("erode image", erodeImage);
   }
}

  

三.形态学滤波算法

形态学的高级操作,往往都建立在基础的膨胀和腐蚀的操作之上

1.开运算:开运算是一个先腐蚀,后膨胀的过程,用于在图像中消除小的物体,在纤细点处分离物体,在平滑化较大的物体的边界的同时不明显改变物体的体积.

2.闭运算:先膨胀后腐蚀的过程,能够用于消除物体中的小型黑洞

3.形态学梯度:膨胀图和腐蚀图之差,对二值图像进行这一操作,可以将团块的边缘突出来,可以使用形态学梯度来保留物体的边缘轮廓.

4.顶帽:源图像和开运算的结果的差值,往往用来分离比邻近点亮一点的斑块,在一幅图具体大幅的背景,而微小物体有比较有规律的情况下,可以使用top_hat运算进行背景的提取

5.黑帽:闭运算的结果与源图像之差,突出了比源图像轮廓周围更暗的区域,往往用于分离比邻近点暗一些的斑块.

核心API:void morpholgyEx(源,目标,int 形态学操作标志,mat 形态学操作内核,Point 锚点,int 迭代次数,int 边界模式,int 边界为常数时的边界值).

注:形态学操作标志的取值如下:MORPH_OPEN开运算  MORPH_CLOSE 闭运算 MORPH_GRENIENT 形态学梯度 MORPH_TOPHAT顶帽 MORPH_BLACKHAT黑帽 MORPH_ERODE腐蚀 MORPH_DILATE 膨胀

形态学操作内核就是前面膨胀腐蚀使用的内核.

使用范例如下:

1.开运算 闭运算 形态学梯度三者联合

//源¡ä图ª?像?
Mat srcImage;

//开a运?算?
const int g_openIterMax = 100;
int g_nopenIterValue;
const int g_openCoreMax = 100;
int g_nopenCoreValue;
Mat openImage;
void OnopenIterTrackbar(int pos,void* userData);
void onopenCoreSizeTrackBar(int pos,void* userData);

//闭À?运?算?
const int g_closeIterMax = 100;
int g_ncloseIterValue;
const int g_closeCoreMax = 100;
int g_ncloseCoreValue;
Mat closeImage;
void OncloseIterTrackbar(int pos,void* userData);
void oncloseCoreSizeTrackBar(int pos,void* userData);

//形?态¬?学¡ì梯¬Y度¨¨
const int g_gredientIterMax = 100;
int g_ngredientIterValue;
const int g_gredientCoreMax = 100;
int g_ngredientCoreValue;
Mat gredientImage;
void OngredientIterTrackbar(int pos,void* userData);
void ongredientCoreSizeTrackBar(int pos,void* userData);

int main(int argc,char* argv[])
{
   srcImage = imread("F:\\opencv\\OpenCVImage\\morpholgy.jpg");

   g_nopenIterValue = 1;
   g_nopenCoreValue = 5;
   namedWindow("open image");
   createTrackbar("iter count", "open image", &g_nopenIterValue, g_openIterMax,OnopenIterTrackbar,0);
   createTrackbar("core size", "open image", &g_nopenCoreValue, g_openCoreMax,onopenCoreSizeTrackBar,0);
   onopenCoreSizeTrackBar(g_nopenCoreValue, 0);

   g_ncloseCoreValue = 5;
   g_ncloseIterValue = 1;
   namedWindow("close image");
   createTrackbar("iter count", "close image", &g_ncloseIterValue, g_closeIterMax,OncloseIterTrackbar,0);
   createTrackbar("core size", "close image", &g_ncloseCoreValue, g_closeCoreMax,oncloseCoreSizeTrackBar,0);
   oncloseCoreSizeTrackBar(g_ncloseCoreValue, 0);

   g_ngredientCoreValue = 5;
   g_ngredientIterValue = 1;
   namedWindow("gredient image");
   createTrackbar("iter count", "gredient image", &g_ngredientIterValue, g_gredientIterMax,OngredientIterTrackbar,0);
   createTrackbar("core size", "gredient image", &g_ngredientCoreValue, g_gredientCoreMax,OngredientIterTrackbar,0);
   OngredientIterTrackbar(g_ngredientIterValue, 0);

   imshow("src image", srcImage);

   moveWindow("src image", 0, 0);
   moveWindow("open image", srcImage.cols, 0);
   moveWindow("close image", srcImage.cols*2, 0);
   moveWindow("gredient image", srcImage.cols*3, 0);

   waitKey(0);
   return 0;
}

void OnopenIterTrackbar(int pos,void* userData)
{
   if(g_nopenCoreValue == 0||g_nopenIterValue == 0)
   {
       imshow("open image", srcImage);
   }
   else
   {
       if(g_nopenCoreValue%2 == 0)
           g_nopenCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nopenCoreValue,g_nopenCoreValue));
       morphologyEx(srcImage, openImage, MORPH_OPEN, core,Point(-1,-1),g_nopenIterValue);
       imshow("open image", openImage);
   }
}
void onopenCoreSizeTrackBar(int pos,void* userData)
{
   if(g_nopenCoreValue == 0||g_nopenIterValue == 0)
   {
       imshow("open image", srcImage);
   }
   else
   {
       if(g_nopenCoreValue%2 == 0)
           g_nopenCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nopenCoreValue,g_nopenCoreValue));
       morphologyEx(srcImage, openImage, MORPH_OPEN, core,Point(-1,-1),g_nopenIterValue);
       imshow("open image", openImage);
   }
}
void OncloseIterTrackbar(int pos,void* userData)
{
   if(g_ncloseCoreValue == 0||g_ncloseIterValue == 0)
   {
       imshow("close image", srcImage);
   }
   else
   {
       if(g_ncloseCoreValue%2 == 0)
           g_ncloseCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_ncloseCoreValue,g_ncloseCoreValue));
       morphologyEx(srcImage, closeImage, MORPH_CLOSE, core,Point(-1,-1),g_ncloseIterValue);
       imshow("close image", closeImage);
   }
}
void oncloseCoreSizeTrackBar(int pos,void* userData)
{
   if(g_ncloseCoreValue == 0||g_ncloseIterValue == 0)
   {
       imshow("close image", srcImage);
   }
   else
   {
       if(g_ncloseCoreValue%2 == 0)
           g_ncloseCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_ncloseCoreValue,g_ncloseCoreValue));
       morphologyEx(srcImage, closeImage, MORPH_CLOSE, core,Point(-1,-1),g_ncloseIterValue);
       imshow("close image", closeImage);
   }
}
void OngredientIterTrackbar(int pos,void* userData)
{
   if(g_ngredientCoreValue == 0||g_ngredientIterValue == 0)
   {
       imshow("gredient image", srcImage);
   }
   else
   {
       if(g_ngredientCoreValue%2 == 0)
           g_ngredientCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_ngredientCoreValue,g_ngredientCoreValue));
       morphologyEx(srcImage, gredientImage, MORPH_GRADIENT, core,Point(-1,-1),g_ngredientIterValue);
       imshow("gredient image", gredientImage);
   }
}
void ongredientCoreSizeTrackBar(int pos,void* userData)
{
   if(g_ngredientCoreValue == 0||g_ngredientIterValue == 0)
   {
       imshow("gredient image", srcImage);
   }
   else
   {
       if(g_ngredientCoreValue%2 == 0)
           g_ngredientCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_ngredientCoreValue,g_ngredientCoreValue));
       morphologyEx(srcImage, gredientImage, MORPH_GRADIENT, core,Point(-1,-1),g_ngredientIterValue);
       imshow("gredient image", gredientImage);
   }
}

  

2. 顶帽 黑帽结合

Mat srcImage;

//顶£¤帽¡À tophat
const int g_tophatIterMax = 100;
int g_ntophatIterValue;
const int g_tophatCoreMax = 100;
int g_ntophatCoreValue;
Mat tophatImage;
void OntophatIterTrackbar(int pos,void* userData);
void ontophatCoreSizeTrackBar(int pos,void* userData);

//黑¨²帽¡À
const int g_blackhatIterMax = 100;
int g_nblackhatIterValue;
const int g_blackhatCoreMax = 100;
int g_nblackhatCoreValue;
Mat blackhatImage;
void OnblackhatIterTrackbar(int pos,void* userData);
void onblackhatCoreSizeTrackBar(int pos,void* userData);

int main(int argc,char* argv[])
{
   srcImage = imread("F:\\opencv\\OpenCVImage\\morpholgy.jpg");

   g_ntophatIterValue = 1;
   g_ntophatCoreValue = 5;
   namedWindow("tophat image");
   createTrackbar("iter count", "tophat image", &g_ntophatIterValue, g_tophatIterMax,OntophatIterTrackbar,0);
   createTrackbar("core size", "tophat image", &g_ntophatCoreValue, g_tophatCoreMax,ontophatCoreSizeTrackBar,0);
   ontophatCoreSizeTrackBar(g_ntophatCoreValue, 0);

   g_nblackhatCoreValue = 5;
   g_nblackhatIterValue = 1;
   namedWindow("blackhat image");
   createTrackbar("iter count", "blackhat image", &g_nblackhatIterValue, g_blackhatIterMax,OnblackhatIterTrackbar,0);
   createTrackbar("core size", "blackhat image", &g_nblackhatCoreValue, g_blackhatCoreMax,onblackhatCoreSizeTrackBar,0);
   onblackhatCoreSizeTrackBar(g_nblackhatCoreValue, 0);

   imshow("src image", srcImage);

   moveWindow("src image", 0, 0);
   moveWindow("tophat image", srcImage.cols, 0);
   moveWindow("blackhat image", srcImage.cols*2, 0);

   waitKey(0);
   return 0;
}

void OntophatIterTrackbar(int pos,void* userData)
{
   if(g_ntophatCoreValue == 0||g_ntophatIterValue == 0)
   {
       imshow("tophat image", srcImage);
   }
   else
   {
       if(g_ntophatCoreValue%2 == 0)
           g_ntophatCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_ntophatCoreValue,g_ntophatCoreValue));
       morphologyEx(srcImage, tophatImage, MORPH_TOPHAT, core,Point(-1,-1),g_ntophatIterValue);
       imshow("tophat image", tophatImage);
   }
}
void ontophatCoreSizeTrackBar(int pos,void* userData)
{
   if(g_ntophatCoreValue == 0||g_ntophatIterValue == 0)
   {
       imshow("tophat image", srcImage);
   }
   else
   {
       if(g_ntophatCoreValue%2 == 0)
           g_ntophatCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_ntophatCoreValue,g_ntophatCoreValue));
       morphologyEx(srcImage, tophatImage, MORPH_TOPHAT, core,Point(-1,-1),g_ntophatIterValue);
       imshow("tophat image", tophatImage);
   }
}

void OnblackhatIterTrackbar(int pos,void* userData)
{
   if(g_nblackhatCoreValue == 0||g_nblackhatIterValue == 0)
   {
       imshow("blackhat image", srcImage);
   }
   else
   {
       if(g_nblackhatCoreValue%2 == 0)
           g_nblackhatCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nblackhatCoreValue,g_nblackhatCoreValue));
       morphologyEx(srcImage, blackhatImage, MORPH_BLACKHAT, core,Point(-1,-1),g_nblackhatIterValue);
       imshow("blackhat image", blackhatImage);
   }
}
void onblackhatCoreSizeTrackBar(int pos,void* userData)
{
   if(g_nblackhatCoreValue == 0||g_nblackhatIterValue == 0)
   {
       imshow("blackhat image", srcImage);
   }
   else
   {
       if(g_nblackhatCoreValue%2 == 0)
           g_nblackhatCoreValue++;
       Mat core = getStructuringElement(MORPH_RECT, Size(g_nblackhatCoreValue,g_nblackhatCoreValue));
       morphologyEx(srcImage, blackhatImage, MORPH_BLACKHAT, core,Point(-1,-1),g_nblackhatIterValue);
       imshow("blackhat image", blackhatImage);
   }
}

  

时间: 03-05

OPENCV形态学操作1的相关文章

EasyPR--开发详解(4)形态学操作、尺寸验证、旋转等操作

在上一篇深度分析与调优讨论中,我们介绍了高斯模糊,灰度化和Sobel算子.在本文中,会分析剩余的定位步骤. 根据前文的内容,车牌定位的功能还剩下如下的步骤,见下图中未涂灰的部分. 图1 车牌定位步骤 我们首先从Soble算子分析出来的边缘来看.通过下图可见,Sobel算子有很强的区分性,车牌中的字符被清晰的描绘出来,那么如何根据这些信息定位出车牌的位置呢? 图2 Sobel后效果 我们的车牌定位功能做了个假设,即车牌是包含字符图块的一个最小的外接矩形.在大部分车牌处理中,这个假设都能工作的很好.

基于形态学操作提取水平和垂直线条

目的: 结合自定义核,应用两个非常常见的形态学算子(例如,扩张和侵蚀),提取水平和垂直方向的线条.将会用到以下OpenCV函数: cv::erode cv::dilate cv::getStructuringElement 接下里的例子是从乐谱中提取音符(五线谱中音符和乐谱线的分离) 理论 Morphology Operations 形态学是一组图像处理操作, 基于预定义的structuring elements(也被称为核).输出图像中的每个像素的值是基于中心像素与输入图像中相邻像素的值的比较

形态学操作实现

数学形态学的基本思想是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的.数学形态学的基本运算有四个:腐蚀.膨胀.开和闭.基于这些基本运算还可以推导和组合成各种数学形态学实用算法.本实验分别实现针对二值图像和灰度图像的四种形态学操作. 一.二值图像的腐蚀.膨胀.开.闭操作 实验结果: 二.灰度图像的腐蚀.膨胀.开.闭操作 实验结果: 代码:(下载链接) %本实验完成对二值图像和灰度图像的腐蚀.膨胀.开.闭操作 close all; clear all; grayI

OpenCV —— 矩阵操作

多通道的矩阵 -- 通道是连续的!! 要将指向该数据类型的指针移动到下一通道,我们只需要将其增加1.如果想访问下一个"像素"或者元素集,则需要一定的偏移量 矩阵的step元素是矩阵中行的长度,单位为字节.   #include "cv.h" #include "highgui.h" #include <IOSTREAM.H> int main(int argc,char** argv) { float vals[]={0.85,-0.

cvMorphologyEx 形态学操作:开闭运算,形态学梯度,礼帽和黑帽

1.开运算:CV_MOP_OPEN,先腐蚀(cvErode)再膨胀(cvDilate),去除亮点,可以将做了阀值化细胞图像的细胞分开 2.闭运算:CV_MOP_CLOSE,先膨胀(cvDilate)再cvErode,去除暗点 3.形态学梯度:cvDilate-cvErode,用于求边界 4.礼帽:src-开运算,突出亮点 5.黑帽:闭运算-src,突出暗点 程序: 代码: #include "cv.h" #include "cxcore.h" #include &q

OpenCV读写操作

OpenCV读取一副图片 imread( const String& filename, int flags = IMREAD_COLOR ); 参数1.文件名(路径与文件名,如果文件在目录中可以直接使用文件名即可) 参数2.读取方式 flags > 0  返回一个3通道的彩色图像 flags = 0  返回一个灰度图像 flags < 0  返回包含Alpha通道的加载图像 OpenCV写入一副图片 //如果目标文件夹内有同名文件则不执行任何操作, 包括下方的任何操作 imwrite

[opencv]像素操作的数字图像处理

之前几天捣鼓matlab,用来处理数字图像,矩阵操作什么的,如果忘记线性代数就真的GG了. 在用了matlab被深深地吐槽之后,决定改用opencv,C++貌似也是处理数字图像的很好的工具 1. 在ubuntu上安装opencv 教程可以百度之,都很详细的 2. 像素处理图像: (1)根据输入的数据,用邻近取样插值法,缩放图像 邻近取样插值法原理:http://blog.chinaunix.net/uid-27675161-id-3452025.html   (2)根据输入,改变数字图像的灰度分

OPENCV形态学算法-2

一.漫水填充算法 该算法通过一个指定的种子点,来分析整张图片上的像素,并设置像素差异阈值,在阈值类的点,最后变成相同的颜色.该方法通过上下限和连通方式来达到不同的连通效果. 该方法常用与标记和分离图像的一部分,以便于对其做进一步的分析和处理,填充的结果总是连通的区域. API:void floodFill(源图像,掩码,Point 种子点,scaral 染色值,Rect* 重绘区域的最小边界矩形区域,scaral 与种子点颜色的负差最大值,scaral 与种子点颜色的正差最大值,int 操作方式

【温故知新】形态学操作

腐蚀:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0. 膨胀:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1. 开:先腐蚀后膨胀.“容易记的话,开最后落在扩大上,所以是膨胀” 闭:先膨胀后腐蚀.“容易记的话,闭最后落在缩小上,所以是腐蚀” 腐蚀:名为腐蚀,肯定是缩小的趋势,能够缩小边界,去除噪点: