图像处理开运算与闭运算

2012-11-17 09:04:27 Vast_Sea 阅读数 24448


From:  http://www.dakaren.com/index.php/archives/196.htm


一、腐蚀和膨胀

  形态学是一门新兴科学,它的用途主要是获取物体拓扑和结果信息,它通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。它在图像处理中的应用主要是:

  1.利用形态学的基本运算,对图像进行观察和处理,从而达到改善图像质量的目的;

  2.描述和定义图像的各种几何参数和特征,如面积,周长,连通度,颗粒度,骨架和方向性。

  限于篇幅,我们只介绍简单二值图像的形态学运算,对于灰度图像的形态学运算,有兴趣的读者可以看有关的参考书。二值图像基本的形态学运算是腐蚀和膨胀,简单的腐蚀是消除物体的所有边界点的一种过程,其结果是使剩下的物体沿其周边比原物体小一个像素的面积。如果物体是圆的,它的直径在每次腐蚀后将减少两个像素,如果物体在某一点处任意方向上连通的像素小于三个,那么该物体经过一次腐蚀后将在该点处分裂为二个物体。简单的膨胀运算是将与某物体接触的所有背景点合并到该物体中的过程。过程的结果是使物体的面积增大了相应数量的点,如果物体是圆的,它的直径在每次膨胀后将增大两个像素。如果两个物体在某一点的任意方向相隔少于三个像素,它们将在该点连通起来。

  下面给出具体的实现腐蚀和膨胀的函数代码:

////////////////////////////////二值图像腐蚀操作函数
BOOL ImageErosion(BYTE *pData,int Width,int Height)
{//pData为图像数据的指针,Width和Height为图像的宽和高;
BYTE* pData1;
int m,n,i,j,sum,k,sum1;
BOOL bErosion;
if(pData==NULL)
{
AfxMessageBox(“图像数据为空,请读取图像数据”);
return FALSE;
}
//申请空间,pData1存放处理后的数据;
pData1=(BYTE*)new char[WIDTHBYTES(Width*8)*Height];
if(pData1==NULL)
{
AfxMessageBox(“图像缓冲数据区申请失败,请重新申请图像数据缓冲区”);
return FALSE ;
}
memcpy(pData1,pData,WIDTHBYTES(Width*8)*Height);
for(i=10;i<Height-10;i++)
for(j=32;j<Width-32;j++)
{
bErosion=FALSE;
sum=*(pData+WIDTHBYTES(Width*8)*i+j);
if(sum==255)
{
//求像素点八邻域的灰度均值;
for(m=-1;m<2;m++)
{
for(n=-1;n<2;n++)
{
sum1=*(pData+WIDTHBYTES(Width*8)*(i+m)+j+n);
if(sum1==0)
{
*(pData1+WIDTHBYTES(Width*8)*i+j)=0;
bErosion=TRUE;
break;
}
}
if(bErosion)
{
bErosion=FALSE;
break;
}
}
}
}
memcpy(pData,pData1,WIDTHBYTES(Width*8)*Height);
return TRUE;
}
////////////////////////////////////二值图像的膨胀操作
BOOL ImageDilation(BYTE *pData,int Width,int Height)
{
BYTE* pData1;
int m,n,i,j,sum,k,sum1;
BOOL bDilation;
if(pData==NULL)
{
AfxMessageBox(“图像数据为空,请读取图像数据”);
return FALSE;
}
//申请空间,pData1存放处理后的数据;
pData1=(BYTE*)new char[WIDTHBYTES(Width*8)*Height];
if(pData1==NULL)
{
AfxMessageBox(“图像缓冲数据区申请失败,请重新申请图像数据缓冲区”);
return FALSE ;
}
memcpy(pData1,pData,WIDTHBYTES(Width*8)*Height);
for(i=10;i<Height-10;i++)
for(j=32;j<Width-32;j++)
{
bDilation=FALSE;
sum=*(pData+WIDTHBYTES(Width*8)*i+j);
if(sum==0)
{
//求像素点八邻域的灰度值;
for(m=-1;m<2;m++)
{
for(n=-1;n<2;n++)
{
sum1=*(pData+WIDTHBYTES(Width*8)*(i+m)+j+n);
if(sum1==255)
{
*(pData1+WIDTHBYTES(Width*8)*i+j)=255;
bDilation=TRUE;
break;
}
}
if(bDilation)
{
bDilation=FALSE;
break;
}
}
}
}
memcpy(pData,pData1,WIDTHBYTES(Width*8)*Height);
return TRUE;
}

  从上面的说明可以看出,腐蚀可以消除图像中小的噪声区域,膨胀可以填补物体中的空洞。对一个图像先进行腐蚀运算然后再膨胀的操作过程称为开运算,它可以消除细小的物体、在纤细点处分离物体、平滑较大物体的边界时不明显的改变其面积。如果对一个图像先膨胀然后再收缩,我们称之为闭运算,它具有填充物体内细小的空洞、连接邻近物体、在不明显改变物体面积的情况下平滑其边界的作用。通常情况下,当有噪声的图像用阈值二值化后,所得到的边界是很不平滑的,物体区域具有一些错判的孔洞,背景区域散布着一些小的噪声物体,连续的开和闭运算可以显著的改善这种情况,这时候需要在连接几次腐蚀迭代之后,再加上相同次数的膨胀,才可以产生所期望的效果。为了更好的显示出二值图像的处理效果,我们仍旧以图像采集卡获取的汽车图像为处理源图像,下图为处理后的效果:


(a)噪声图

(b)开运算处理

    图一 开运算效果图

  上图中,a图为包含噪声的图像,b图为经过腐蚀膨胀处理后的图像,可以看出,经过上述处理,成功的消除了图像中的噪声点,同时又起到了平滑边缘的作用。


2019-05-03 22:14:29 zaishuiyifangxym 阅读数 3622

目录

1 图像开运算(先腐蚀,后膨胀)

1.1 基本原理

1.2 代码示例

2 图像闭运算(先膨胀,后腐蚀)

2.1 基本原理

2.2 代码示例

3 图像梯度运算(膨胀 — 腐蚀)

3.1 基本原理

3.2 代码示例

参考资料


前面介绍了 形态学处理——图像腐蚀与图像膨胀,图像膨胀会扩大一幅图像的组成部分,而图像腐蚀会缩小一幅图像的组成部分。下面将继续介绍形态学处理中的开操作和闭操作。

开操作一般会平滑物体的轮廓、断开较窄的狭颈并消除细的突出物。

闭操作同样也会平滑轮廓的一部分。但与开操作相反,它通常会弥合较窄的间断和细长的沟壑,消除小的孔洞,填补轮廓线中的断裂。

 

1 图像开运算(先腐蚀,后膨胀)

1.1 基本原理

图像开运算是图像依次经过腐蚀、膨胀处理后的过程。图像被腐蚀后,去除了噪声,但是也压缩了图像;接着对腐蚀过的图像进行膨胀处理,可以去除噪声,并保留原有图像。如下图所示:

开运算:先腐蚀,后膨胀

 

下图借鉴是一篇博客写的开运算效果图:

 

1.2 代码示例

图像开运算使用函数 morphologyEx() ,它是形态学扩展的一组函数,其参数cv2.MORPH_OPEN对应开运算

morphologyEx() 函数形式如下:

dst = cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)

其中,参数:

dst 表示处理的结果;

src 表示原始图像;

cv2.MORPH_OPEN 表示开运算;

kernel 表示卷积核。

例如下图表示 5\times5 的卷积核,可以采用函数 np.ones((5,5), np.uint8) 构建。

 

(1)卷积核大小为5\times

代码如下所示:

#encoding:utf-8
import cv2
import numpy as np

#读取图片
src = cv2.imread('test3.bmp', cv2.IMREAD_UNCHANGED)

#设置卷积核
kernel = np.ones((5,5), np.uint8)

#图像开运算
result = cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

运行结果如下图所示:

由上面结果可以看到,仍然有噪声存在,可以将增大卷积核的大小。

 

(2)卷积核大小为25\times25 

代码如下所示:

#encoding:utf-8
import cv2
import numpy as np

#读取图片
src = cv2.imread('test3.bmp', cv2.IMREAD_UNCHANGED)

#设置卷积核
kernel = np.ones((25,25), np.uint8)

#图像开运算
result = cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

运行结果如下图所示:

 


 

2 图像闭运算(先膨胀,后腐蚀)

2.1 基本原理

图像闭运算是图像依次经过膨胀、腐蚀处理后的过程。图像先膨胀,后腐蚀,它有助于关闭前景物体内部的小孔,或物体上的小黑点。如下图所示:

闭运算:先膨胀,后腐蚀

 

下图借鉴是一篇博客写的开运算效果图:

 

 

2.2 代码示例

图像闭运算使用函数 morphologyEx() , 它是形态学扩展的一组函数,其参数 cv2.MORPH_CLOSE 对应闭运算

morphologyEx() 函数形式如下:

dst = cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)

其中,参数:

dst 表示处理的结果;

src 表示原图像;

cv2.MORPH_CLOSE 表示闭运算;

kernel表示卷积核。

例如,下图表示 5\times5 的卷积核,可以采用函数 np.ones((5,5), np.uint8) 构建。

 

(1)卷积核大小为 5\times

代码如下所示:

#encoding:utf-8
import cv2
import numpy as np

#读取图片
src = cv2.imread('test4.bmp', cv2.IMREAD_UNCHANGED)

#设置卷积核
kernel = np.ones((5,5), np.uint8)

#图像闭运算
result = cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

运行结果如下图所示:

由上面结果可以看到,噪声仍有一处存在,可以将增大卷积核的大小。

 

(2)卷积核大小为 7\times

代码如下所示:

#encoding:utf-8
import cv2
import numpy as np

#读取图片
src = cv2.imread('test4.bmp', cv2.IMREAD_UNCHANGED)

#设置卷积核
kernel = np.ones((7,7), np.uint8)

#图像闭运算
result = cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

运行结果如下图所示:

 


 

3 图像梯度运算(膨胀 — 腐蚀)

3.1 基本原理

图像梯度运算是膨胀图像减去腐蚀图像的结果,得到图像的轮廓,其中二值图像1表示白色点,0表示黑色点。 如下图所示:

梯度运算:膨胀图像 — 腐蚀图像

 

3.2 代码示例

图像梯度运算使用的函数 morphologyEx(),其参数 cv2.MORPH_GRADIENT 对应 梯度运算

morphologyEx() 函数形式如下:

dst = cv2.morphologyEx(src, cv2.MORPH_GRADIENT, kernel)

其中,参数:

dst表示处理的结果;,

src表示原图像;,

cv2.MORPH_GRADIENT表示梯度运算;,

kernel表示卷积核。

例如,下图表示 5\times5 的卷积核,可以采用函数 np.ones((5,5), np.uint8) 构建。

 

代码如下所示:

#encoding:utf-8
import cv2
import numpy as np

#读取图片
src = cv2.imread('test4.bmp', cv2.IMREAD_UNCHANGED)

#设置卷积核
kernel = np.ones((7,7), np.uint8)

#图像闭运算
result = cv2.morphologyEx(src, cv2.MORPH_GRADIENT, kernel)

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

运行结果如下图所示:

 


 

参考资料

[1] https://blog.csdn.net/Eastmount/article/details/83651172

[2] https://blog.csdn.net/hanshanbuleng/article/details/80657148

[3] Python+OpenCV图像处理

2018-07-27 20:05:06 weixin_41929524 阅读数 10146

1. 回顾

简单的图像处理——1. 图像的形态学操作:膨胀与腐蚀 中,我们介绍了图像基本的形态学操作——膨胀腐蚀,同时也利用了Python进行了实现。在这里我们将接着上次的内容,接着描述其它的一些图像形态学操作方法,以及相应的Python实现。

下面我们同样以这只小鸟为例,来看看图像其它的形态学算法。
这里写图片描述


2. 图像的开运算

开运算的具体实现:通过先进行腐蚀操作,再进行膨胀操作得到。我们在移除小的对象时候很有用(假设物品是亮色,前景色是黑色),被用来去除噪声

我们先以二值图为例,其如下所示。左侧是原始图像,右侧是应用开运算之后的图像。我们可以看到左侧图像小的黑色空间被填充消失,所以开运算可以进行白色的孔洞填补。因为可以想象,我们先将黑色区域变大,然后填充部分白色区域,白色小区域这时就会被抹去,然后膨胀再将黑色区域变回,但是抹去的部分会消失,则会达到下面的效果。


而对于彩色图而言,则是将一些小的偏白色孔洞或者区域用周围的颜色进行填补,整体的图像也会模糊化,宛如一幅水彩画。

下面分别是卷积核为10与50像素开运算处理后的效果,可以发现眼部与羽毛中的白色部分均被填充,地面上的气泡也接近模糊消失了。

这里写图片描述
这里写图片描述


3. 图像的闭运算

闭运算是开运算的一个相反的操作,具体是先进行膨胀然后进行腐蚀操作。通常是被用来填充前景物体中的小洞,或者抹去前景物体上的小黑点。因为可以想象,其就是先将白色部分变大,把小的黑色部分挤掉,然后再将一些大的黑色的部分还原回来,整体得到的效果就是:抹去前景物体上的小黑点了。

二值图进行闭运算则会是如下的效果,左侧是原图,右侧是进行闭运算之后的图。


下面分别是卷积核为10与50像素闭运算处理后的效果,可以发现左眼的黑色部分变小了,以及双腿在大卷积核进行处理时,直接会消失,这是由于因为腿比较细。然后图像整体会变白一些。

这里写图片描述
这里写图片描述

而开闭运算直接的抹除小区域的体现如下:
这里写图片描述

后面我们会继续介绍图像的形态学梯度以及顶帽变换与底帽变换。

2018-06-11 20:16:42 hanshanbuleng 阅读数 31016

(如果不了解腐蚀与膨胀原理的同学那请看我前一期博客哦!)

  • 1.开运算
    开运算 = 先腐蚀运算,再膨胀运算(看上去把细微连在一起的两块目标分开了)
    开运算的效果图如下图所示:
    这里写图片描述
  • 开运算总结:
    (1)开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不便。
    (2)开运算是一个基于几何运算的滤波器。
    (3)结构元素大小的不同将导致滤波效果的不同。
    (4)不同的结构元素的选择导致了不同的分割,即提取出不同的特征。

  • 2.闭运算
    闭运算 = 先膨胀运算,再腐蚀运算(看上去将两个细微连接的图块封闭在一起)
    闭运算的效果图如下图所示:

这里写图片描述
- 闭运算总结:
(1)闭运算能够填平小湖(即小孔),弥合小裂缝,而总的位置和形状不变。
(2)闭运算是通过填充图像的凹角来滤波图像的。
(3)结构元素大小的不同将导致滤波效果的不同。
(4)不同结构元素的选择导致了不同的分割。


我们可以使用opencv自带函数进行调试哦!
openCV里有一个很好的函数getStructuringElement,我们只要往这个函数传相应的处理参数,就可以进行相应的操作了,使用起来非常方便。下面我简单列举一下相应的操作宏定义:

标识符 含义
MORPH_OPEN 开运算
MORPH_CLOSE 闭运算
MORPH_ERODE 腐蚀
MORPH_DILATE 膨胀

我就简单举个例子:

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("寒山不冷.jpg");
    namedWindow("原始图", WINDOW_NORMAL);
    imshow("原始图", img);
    Mat out;
    //获取自定义核 第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的
    Mat element = getStructuringElement(MORPH_RECT, Size(18, 18)); 


    //具体要选择哪种操作,就修改第三个参数就可以了。这里演示的是形态学开运算处理
    morphologyEx(img, out, MORPH_OPEN, element);
    namedWindow("形态学处理操作", WINDOW_NORMAL);
    imshow("形态学处理操作", out);
    waitKey(0);

}
2019-02-14 16:55:37 freehawkzk 阅读数 1106

【图像处理】-021 开运算和闭运算

  上一篇中说到了图像的形态学操作,介绍了腐蚀和膨胀。由于腐蚀和膨胀都会对目标的面积产生较大的影响(依据操作元素的大小),影响图像中正常目标的判断。在形态学操作中,还有开运算和闭运算操作,操作结果对目标的尺寸只有较小的影响。开运算一般会平滑物体的轮廓、断开较窄的狭颈并消除细的突出物。闭运算也会平滑轮廓的一部分,通常会弥合较窄的间断和细长的沟壑,消除小的孔洞,填补轮廓线中的断裂。

1 开运算

  结构元BB对集合AA的开操作,表示为ABA\circ B,其定义如下:
(1)AB=(AB)B A \circ B =(A\circleddash B)\bigoplus B \tag{1}
BBAA的开操作就是BBAA的腐蚀,紧接着用B对结果进行膨胀,也就是用结构元素B,先对A进行腐蚀操作,在对腐蚀结果进行膨胀操作。

2 闭运算

  用结构元B对集合A的闭运算,表示为ABA\cdot B,其定义如下:
(2)AB=(AB)B A\cdot B=(A\bigoplus B)\circleddash B \tag{2}
B对集合A的闭运算,就是先用B对A进行膨胀,然后对结果用B进行腐蚀,先膨胀后腐蚀。

3 实现

#include "../Include/baseOps.h"
int main()
{
	//OutputDebugString(L"AB");
	SetCurrentDirectoryToExePath();
	cv::Mat src = cv::imread("../images/72.png");
	cv::imshow("原图", src);

	cv::Mat bw;
	cv::threshold(src, bw, 125, 255, cv::THRESH_BINARY);
	cv::imshow("125阈值二值化", bw);

	cv::Mat m = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
	cv::Mat dst;
	cv::morphologyEx(bw, dst, cv::MORPH_ERODE, m);
	cv::imshow("腐蚀", dst);

	cv::morphologyEx(bw, dst, cv::MORPH_DILATE, m);
	cv::imshow("膨胀", dst);

	cv::morphologyEx(bw, dst, cv::MORPH_OPEN, m);
	cv::imshow("开运算", dst);

	cv::morphologyEx(bw, dst, cv::MORPH_CLOSE, m);
	cv::imshow("闭运算", dst);
	cv::waitKey(0);

	return 0;
}

在这里插入图片描述

开运算与闭运算

阅读数 7171