二值图像的膨胀运算及其VC实现
数字图像处理_第八章二值图像处理2

图(d) : N (4) (0 0) (0 0) (0 0) (0 0) 0; N (8) (1 0) (1 0) (1 1) (1 0) 3. 图(e) : N (4) (1 0) (1 0) (1 0) (1 0) 4; N (8) (0 0) (0 0) (0 0) (0 0) 0. 图(f ) : N (4) (0 0) (0 0) (0 0) (0 0) 0; N (8) (1 0) (1 0) (1 0) (1 0) 4.
原图
四连接定义下
八连接定义下
在四连接定义下,内部点是“在当前点的八近邻像素点中没有值为0 的点”,而在八连接定义中,内部点是“在当前点的四近邻像素点中 没有值为0的点”。
2013-8-7 4
10.1.3 连接数与交叉数
连接数:是指沿着当前点的近邻(四近邻或者八近邻)像 素所构成的边界轨迹上移动时,通过的像素值为1的点的 个数。 四近邻下的连接数定义:
判断该结构元素所覆盖范围内的像素值是否至少有一个为1如果是则膨胀后的图像的相同位置上的像素值为1如果该覆盖范围内的所有像素值为0则膨胀后图像的相同位置上的像素值0101000110100010000011000000001011111110011010011100001100000000原图像原图像结构元素结构元素膨胀后的图像膨胀后的图像2012627161022膨胀原图图原膨胀一次次膨胀一膨胀二次次膨胀二膨胀三次次膨胀三201262717103开运算与闭运算腐蚀处理目标物的面积减少
LS N e 2 N o
其中,Ne表示边界ຫໍສະໝຸດ 上的方向码为偶数的像 素个数;No为边界线上方向码为奇数的像素 个数。
《图像处理》实验8:二值图像膨胀、腐蚀

二值图像膨胀、 二值图像膨胀、腐蚀实验步骤
BYTE* TempData=new BYTE[linebytes*infoheader->biHeight]; memset(TempData,0,linebytes*infoh eader->biHeight); //开辟临时空间,存放数据 开辟临时空间, 开辟临时空间
实验八 二值图像膨胀、 二值图像膨胀、腐蚀
矿大信电学院 蔡利梅
一、实验目的
掌握二值图像膨胀、 掌握二值图像膨胀、腐蚀的基本方法 编程实现膨胀、 编程实现膨胀、腐蚀
二、实验原理
膨胀 腐蚀
二值图像膨胀、 二值图像膨胀、腐蚀实验步骤
打开应用程序Clm 打开应用程序 修改程序菜单 添加“二值图像处理”下拉菜单, 添加“二值图像处理”下拉菜单,并添加下 一级子菜单“膨胀” 一级子菜单“膨胀”,ID:ID_DILATION, : , 添加子菜单“腐蚀” 添加子菜单“腐蚀”,ID:ID_EROSION : 创建菜单项“膨胀” 腐蚀” 创建菜单项“膨胀” 、“腐蚀”的消息响 应函数OnDilation() 、OnErosion()。(基 。(基 应函数 。( 于CClmDoc类) 类
二值图像膨胀、 二值图像膨胀、腐蚀实验步骤
switch(nbtype) { case 0: nbw=1; nbh=3; break; case 1: nbw=3; nbh=1; break; case 2: nbw=3; nbh=3; break; case 3: nbw=5; nbh=5; break; }
二值图像膨胀、 二值图像膨胀、腐蚀实验步骤
BYTE* TempData=new BYTE[linebytes*infoheader->biHeight]; memset(TempData,255,linebytes*infohe ader->biHeight); //开辟临时空间,存放数据 开辟临时空间, 开辟临时空间
二值形态学基本运算实验报告

3.开运算:
void CImageProcessingDoc::Onimageopening()
{ // TODO: Add your command handler code here CImageProcessingDoc::Onimageerosion();//先调用二值腐蚀 CImageProcessingDoc::Onimagedilation(); //再调用二值膨胀 }
2.腐蚀:
void CImageProcessingDoc::Onimageerosion() { // TODO: Add your command handler code here int m_Width, m_Height, m_SaveWidth; m_Width = m_pDibInit->GetWidth(); m_Height = m_pDibInit->GetHeight(); m_SaveWidth = m_pDibInit->GetSaveWidth(); int i,j; double *y=new double[m_Width*m_Height]; for(j=1;j<m_Height;j++) //将图像数据赋予新开辟内存空间 { for(i=1;i<m_Width;i++) {
二值形态学基本运算实验报告
1、 实验目的
1. 法; 2. 学会二值形态学的基本运算:膨胀、腐蚀、开启和闭合; 3. 掌握膨胀、腐蚀、开启和闭合的物理意义。 掌握二值形态学的思想,进一步掌握图像处理和分析的实用算
2、 实验原理 (1) 膨胀:
;
(2) 腐蚀:
;
(3) 开运算:
;
(4) 闭运算:
C 图像的膨胀和腐蚀

C++图像的膨胀和腐蚀二值图像是一种简单的图像格式,它只有两个灰度级,即"0"表示黑色的像素点,"255"表示白色的像素点,至于如何从一幅普通的图像获得二值图像,请参考我近期在天极网上发表的《Visual C++编程实现图像的分割》一文。
二值图像处理在图像处理领域占据很重要的位置,在具体的图像处理应用系统中,往往需要对于获得的二值图像再进一步进行处理,以有利于后期的识别工作。
二值图像处理运算是从数学形态学下的集合论方法发展起来的,尽管它的基本运算很简单,但是却可以产生复杂的效果。
常用的二值图像处理操作有许多方法,如腐蚀、膨胀、细化、开运算和闭运算等等。
本文对这些内容作些研究探讨,希望对爱好图像处理的朋友有所帮助。
一、腐蚀和膨胀形态学是一门新兴科学,它的用途主要是获取物体拓扑和结果信息,它通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。
它在图像处理中的应用主要是: 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*)newchar[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);}////////////////////////////////////二值图像的膨胀操作BOOL ImageDilation(BYTE *pData,int Width,int Height) {BYTE* pData1;int m,n,i,j,sum,k,sum1;BOOL bDilation;if(pData==NULL){AfxMessageBox("图像数据为空,请读取图像数据");}//申请空间,pData1存放处理后的数据;pData1=(BYTE*)newchar[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;}。
#VC++实现图像二值处理

Visual C++实现二值图像处理二值图像是一种简单的图像格式,它只有两个灰度级,即"0"表示黑色的像素点,"255"表示白色的像素点,至于如何从一幅普通的图像获得二值图像,请参考我近期在天极网上发表的《Visual C++编程实现图像的分割》一文。
二值图像处理在图像处理领域占据很重要的位置,在具体的图像处理应用系统中,往往需要对于获得的二值图像再进一步进行处理,以有利于后期的识别工作。
二值图像处理运算是从数学形态学下的集合论方法发展起来的,尽管它的基本运算很简单,但是却可以产生复杂的效果。
常用的二值图像处理操作有许多方法,如腐蚀、膨胀、细化、开运算和闭运算等等。
本文对这些内容作些研究探讨,希望对爱好图像处理的朋友有所帮助。
一、腐蚀和膨胀形态学是一门新兴科学,它的用途主要是获取物体拓扑和结果信息,它通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。
它在图像处理中的应用主要是:1.利用形态学的基本运算,对图像进行观察和处理,从而达到改善图像质量的目的;2.描述和定义图像的各种几何参数和特征,如面积,周长,连通度,颗粒度,骨架和方向性。
限于篇幅,我们只介绍简单二值图像的形态学运算,对于灰度图像的形态学运算,有兴趣的读者可以看有关的参考书。
二值图像基本的形态学运算是腐蚀和膨胀,简单的腐蚀是消除物体的所有边界点的一种过程,其结果是使剩下的物体沿其周边比原物体小一个像素的面积。
如果物体是圆的,它的直径在每次腐蚀后将减少两个像素,如果物体在某一点处任意方向上连通的像素小于三个,那么该物体经过一次腐蚀后将在该点处分裂为二个物体。
简单的膨胀运算是将与某物体接触的所有背景点合并到该物体中的过程。
过程的结果是使物体的面积增大了相应数量的点,如果物体是圆的,它的直径在每次膨胀后将增大两个像素。
如果两个物体在某一点的任意方向相隔少于三个像素,它们将在该点连通起来。
下面给出具体的实现腐蚀和膨胀的函数代码:////////////////////////////////二值图像腐蚀操作函数从上面的说明可以看出,腐蚀可以消除图像中小的噪声区域,膨胀可以填补物体中的空洞。
腐蚀膨胀算法详细解释

形态学运算中腐蚀,膨胀,开运算和闭运算(针对二值图而言)6.1腐蚀腐蚀是一种消除边界点,使边界向内部收缩的过程。
可以用来消除小且无意义的物体。
腐蚀的算法:用3x3的结构元素,扫描图像的每一个像素用结构元素与其覆盖的二值图像做“与”操作如果都为1,结果图像的该像素为1。
否则为0。
结果:使二值图像减小一圈把结构元素B平移a后得到Ba,若Ba包含于X,我们记下这个a点,所有满足上述条件的a点组成的集合称做X被B腐蚀(Erosion)的结果。
用公式表示为:E(X)={alBa C X}=X©B,如图6.8所示。
图6.8腐蚀的示意图图6.8中X是被处理的对象,B是结构元素。
不难知道,对于任意一个在阴影部分的点a,Ba包含于X,所以X被B腐蚀的结果就是那个阴影部分。
阴影部分在X的范围之内,且比X小,就象X被剥掉了一层似的,这就是为什么叫腐蚀的原因。
值得注意的是,上面的B是对称的,即B的对称集Bv=B,所以X被B腐蚀的结果和X被Bv腐蚀的结果是一样的。
如果B不是对称的,让我们看看图6.9,就会发现X被B腐蚀的结果和X被Bv腐蚀的结果不同。
y图6.9结构元素非对称时,腐蚀的结果不同图6.8和图6.9都是示意图,让我们来看看实际上是怎样进行腐蚀运算的。
在图6.10中,左边是被处理的图象X (二值图象,我们针对的是黑点),中间是结构元素B ,那个标有origin 的点是中心点,即当前处理元素的位置,我们在介绍模板操作时也有过类似的概念。
腐蚀的方法是,拿B 的中心点和X 上的点一个一个地对比,如果B 上的所有点都在X 的范围内,则该点保留,否则将该点去掉;右边是腐蚀后的结果。
可以看出,它仍在原来X 的范围内,且比X 包含的点要少,就象X 被腐蚀掉了一层。
o Q Q Q o & QO Qo Q o O oooo o o o o o 0- 0 O 0 o o •• • ■ Oo o oo o o 0 o o o o o 0 0 o o o ••o o o oo o o o ■ ■ o o 0 0 o o o ••o 0 0 oo o o 0 ■ • ♦ o QQ Q ■0 0 & o Q Q Q 0 0 * * 0 0 0 O 0 0 • ♦ ♦■ 0 Q Q ◎ 00o o ■ •0 0 o O ■ ■ ■ ■ *« O Q Qo o■ ■ ■ ■ Q Q c- O■ * ■ o GO O O O o o •o o ■ •• ■ o o o o O oO ■ ■ ■o 0o O O o O ♦<Q 0■••■ o a o o O o O o o 0 0 o 0oO o oooo\>o0 00o o o o 0 0 0'originFEX e 6图6.10腐蚀运算 图6.11为原图,图6.12为腐蚀后的结果图,能够很明显地看出腐蚀的效果。
python简单图像处理(13)二值图腐蚀和膨胀,开运算、闭运算

python简单图像处理(13)⼆值图腐蚀和膨胀,开运算、闭运算我们直接看图吧我们把粗框内的区域看作原图像假设有⼀个圆在图像空间移动,取⼀个点作为圆的中⼼,若圆的区域被完全包含在原图像中则我们把它放到腐蚀后的区域中若只有⼀部分在原图像区域或没有⼀个点在原图区域中,我们则不会把它放在腐蚀区中显然,粗框区域腐蚀后会变成内部填充框区域⽽膨胀却恰恰相反把粗框线看作原图的话,取原图上⼀点为圆的中⼼,所以在圆的区域都被放在膨胀区显然,膨胀后,原图会变成外边框的区域上⾯,我们是以圆为窗的,事实上你可以使⽤任意窗形,不过最好有⼀个中⼼点好啦,我们来看看利⽤腐蚀和膨胀有什么效果吧import cvdef Two(image):w = image.widthh = image.heightsize = (w,h)iTwo = cv.CreateImage(size,8,1)for i in range(h):for j in range(w):iTwo[i,j] = 0 if image[i,j] <220 else 255return iTwodef Corrode(image):w = image.widthh = image.heightsize = (w,h)iCorrode = cv.CreateImage(size,8,1)kH = range(2)+range(h-2,h)kW = range(2)+range(w-2,w)for i in range(h):for j in range(w):if i in kH or j in kW:iCorrode[i,j] = 255elif image[i,j] == 255:iCorrode[i,j] = 255else:a = []for k in range(5):for l in range(5):a.append(image[i-2+k,j-2+l])if max(a) == 255:iCorrode[i,j] = 255else:iCorrode[i,j] = 0return iCorrodedef Expand(image):w = image.widthh = image.heightsize = (w,h)iExpand = cv.CreateImage(size,8,1)for i in range(h):for j in range(w):iExpand[i,j] = 255for i in range(h):for j in range(w):if image[i,j] == 0:for k in range(5):for l in range(5):if -1<(i-2+k)<h and -1<(j-2+l)<w:iExpand[i-2+k,j-2+l] = 0return iExpandimage = cv.LoadImage('pic3.jpg',0)iTwo = Two(image)iCorrode = Corrode(iTwo)iExpand = Expand(iTwo)cv.ShowImage('image',image)cv.ShowImage('iTwo',iTwo)cv.ShowImage('iCorrode',iCorrode)cv.ShowImage('iExpand',iExpand)cv.WaitKey(0)看看运⾏效果吧第⼀幅图是原图的灰度图,第⼆幅图是对其做了⼆值处理对于⼆值图像来说,对⿊⾊进⾏腐蚀与对⽩⾊进⾏膨胀得到的效果是⼀样的,对⽩⾊进⾏腐蚀与对⿊⾊进⾏膨胀的得到的效果是⼀样的。
腐蚀膨胀的快速实现

腐蚀膨胀的快速实现腐蚀、膨胀作为一种简单、基础的形态学操作,我之前没有过多的关注,直到最近发现OpenCV的实现要比自己的实现快几十倍,才进行了深入研究,发现这个操作也并没有想象中的那么简单。
0.准备工作一般来说,腐蚀和膨胀都是基于二值图像做的,因此我把经典的lena.jpg转换成了二值图像,用于测试效果和性能。
代码如下://convert a RGB image to binaryMat image=imread("/Users/lena.jpg");Mat gray(image.cols,image.rows,CV_8UC1);cvtColor(image,gray,CV_BGR2GRAY);Mat binary(image.cols,image.rows,CV_8UC1);for(int i=0;i<gray.cols*gray.rows*gray.channels();++i){if(gray.data[i]>128)binary.data[i]=255;elsebinary.data[i]=0;}imshow("lena",binary);waitKey(0);转换后的图片如下:1.OpenCV函数接口及其实现方式OpenCV中有dilate和erode两个函数用于膨胀和腐蚀,调用方法如下://opencv dilate&erode functionsMat dilateImg(image.cols,image.rows,CV_8UC1);Mat erodeImg(image.cols,image.rows,CV_8UC1);double dur;clock_t start,end;start = clock();dilate(binary,dilateImg,Mat(),cv::Point(-1,-1),5);end = clock();dur = (double)(end - start);printf("OpenCV dilate Use Time:%f ms\n",(dur/CLOCKS_PER_SEC*1000));start = clock();erode(binary,erodeImg,Mat(),cv::Point(-1,-1),5);end = clock();dur = (double)(end - start);printf("OpenCV erode Use Time:%f ms\n",(dur/CLOCKS_PER_SEC*1000));imshow("dilate",dilateImg);waitKey(0);imshow("erode",erodeImg);waitKey(0);在腐蚀膨胀时,均使用了半径/迭代次数=5。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
二值图像的膨胀运算及其VC实现
本文主要对二值图像膨胀的定义、原理以及VC下实现方法进行总结,并通过图像处理结果对图像膨胀操作的功能以及使用场合进行讨论。
1、定义
参考冈萨雷斯的经典教材,对Z空间中的集合A和B,使用B对
A进行膨胀,可定义为:
可以理解膨胀过程为:首先得到膨胀结构元素相对于自身原点(按照本人的理解,对于对称的结构元素,原点为其对称中心,对于非对称的结构元素,原点由工程师根据相应的应用制定)的映射,然后根据此映射的z平移,如果结构元素的映射与集合A交集非空,则z属于膨胀后的集合。
按照本人的理解,这个定义的意思就是从图像的第一个像素点开始依行遍历全部像素,在每个像素点上,移动结构元素B的映射的中心与其重合,然后判断此位置的结构元素是否有对A集合的覆盖,如果有,
则保留这个点,否则对此点取反(按照如下的符号约定,即将改点灰度值设置为0)。
2、灰度值及逻辑约定
1)二值图像中,所有黑色像素的集合是图像完整的形态学描述
2)对于二值化后的图像:黑色表示灰度为0,白色表示灰度为255 3)对于形态学结构元素:黑色代表1,白色表示0
4)值为1的点组成完整的形态学结构元素
3、VC实现灰度图的二值膨胀
首先贴上代码,然后再进行说明。
作者实现的代码如下:
1./*******************************************************************
******
2.*
3.* \函数名称:
4.* DilationAlgorithm()
5.*
6.* \输入参数:
7.* pGrayMat: 二值图像数据
8.* pErosionMat: 输出的腐蚀图像数据
9.* width: 图形尺寸宽度
10.* height: 图形尺寸高度
11.* nWindows: 腐蚀操作结构元素尺寸,当nWindows=3时,如下:
12.* 1 1 1
13.* 1 1 1
14.* 1 1 1
15.* \返回值:
16.* 无
17.* \函数说明: 实现图像形态学算子-膨胀
18.*
19.**************************************************************
**********/
20.void CDilationDlg::DilationAlgorithm(CvMat *pGrayMat, CvMat *p
ErosionMat, int width, int height, int nWindows)
21.{
22.int nSize = (int)(nWindows/2);
23.for(int i=0; i<height; i++)
24. {
25.for(int j=0; j<width; j++)
26. {
27.int nFlag = 1; //用于控制循环跳出
28.for(int m=i-nSize; m<=i+nSize; m++)
29. {
30.for(int n=j-nSize; n<=j+nSize; n++)
31. {
32.if((m>=0)&&(m<height)&&(n>=0)&&(n<width))
33. {
34.double nData = cvmGet(pGrayMat, m, n);
35.if((nData == 0)) //如果覆盖区域有一个黑
点,则设置保留当前结构元素中心点
36. {
37. nFlag=0;
38.break;
39. }
40. }
41. }
42.if(nFlag==0)
43.break;
44. }
45.if(nFlag==0)
46. {
47.double nData = 0;
48. cvmSet(pErosionMat, i, j, nData);
49. }
50.else
51. {
52.double nData = 255;
53. cvmSet(pErosionMat, i, j, nData);
54. }
55. }
56. }
57.}
对程序实现的主要说明如下:
1)选择腐蚀结构元素:本文对结构元素的选取不做过多的讨论,采用最简单常见的正方形结构元素,其全部像素均为1。
这样一个结构元素相对于其原点的映射还是自身,因此在代码实现中没有进行相关的反射操作。
所实现的函数DilationAlgorithm中最后一个参数用于控制结构元素尺寸。
2)边界处理:由于结构元素有一定的尺寸,因此当结构元素中心移动到图像边缘的若干个像素时,可能有一部分的结构元素超出了图像边界,这是本程序的处理方法是:将图像进行虚拟扩充,扩充的元素灰度值全部填255(根据上文定义,即为无意义的白色像素填充).
3)原始图像选择:所选择图片是白底上面有几个离散的黑点。
这样可容易看出经过膨胀后黑点相对大小的变化。
4、膨胀结果分析
顾名思义,腐蚀操作可以使得图像减小“一圈”,同时腐蚀操作能够将图像中较小的细节消除掉(效果与结构元素形状和尺寸有关)。
以下是程序运行的结果。
(为了能使得图像看起来清晰一点,对每幅图的前景和背景进行了反色处理)
图1 待处理图像反色结果
图2 膨胀结果反色(结构元素尺寸为3)
图3 膨胀结果反色(结构元素尺寸为11)
对比图2与图1可以看出,经过尺寸为3的结构元素膨胀后,4个孤立的点尺寸都变大了,这说明了膨胀操作能够根据结构元素对图像中的有效像素进行扩充;
另外,对比图2与图3可以看到,当结构元素尺寸增大到11时,图中白色圆圈范围内的两个点集被膨胀为一个点,这说明了膨胀操作可以将小的裂缝桥接起来,根据这个功能我们能够对图像断裂进行恢复。
需要注意的是,当结构元素不是对称的时候,必须要对元素先进行自身映射,不然得到的结果是不合理的。