地址http://blog.csdn.net/TonyShengTan/article/details/42426033(参考书:冈萨雷斯的书,《图像处理、分析与机器视觉》)
结构元素:
二维结构元素可以理解成一个二维矩阵,矩阵元素的值为0或者1;通常结构元素要小于待处理的图像。
腐蚀:
把结构元素B平移a后得到Ba,若Ba包含于X,我们记下这个a点,所有满足上述条件的a点组成的集合称做X被B腐蚀(Erosion)的结果。
图中有个错误:第三个图,也就是腐蚀的结果中,黑点没有最左侧一列(两个黑点)。
膨胀(dilation)
可以看做是腐蚀的对偶运算,其定义是:把结构元素B平移a后得到Ba,若Ba击中X,我们记下这个a点。所有满足上述条件的a点组成的集合称做X被B膨胀的结果。
膨胀过程:
说明:左边是被处理的图象X(二值图象,我们针对的是黑点),中间是结构元素B。膨胀的方法是,拿B的中心点和X上的点及X周围的点一个一个地对,如果B上有一个点落在X的范围内,则该点就为黑;右边是膨胀后的结果。可以看出,它包括X的所有范围,就象X膨胀了一圈似的。
开操作与闭操作:
开操作:先腐蚀后膨胀。开操作是将跨度小于结构元的峰顶消去。可以去掉目标外的孤立点。
闭操作:先膨胀后腐蚀是闭操作。将跨度小于结构元的谷底填平。可以去掉目标内的孔。如下图:
图中蓝色为原图,红色为开操作,绿色为闭操作。
顶帽和底帽
顶帽操作和底帽操作是灰度图像所特有的,其原理是开操作将使峰顶消去,具体消去了多少呢,可以用原图减去开操作结果,这样就能得到其消去的部分,而这个过程成为顶帽操作,顶帽就是开操作消去的峰顶,这一部分对应于图像中较亮的部分,也叫白色顶帽。
同理,底帽操作是用闭操作的结果减去原图就得到被闭操作填充的谷底部分,这一部分对应于图像中较暗的部分,也叫黑色底帽。
测地腐蚀与测地膨胀
测地腐蚀与测地膨胀在二值图像中的操作是将腐蚀与膨胀结果与ground做“与”和“或”操作,与灰度膨胀中膨胀的推广一样,“与”和“或”被取代为最大值和最小值。重建操作
重建操作分为很多种,包括重建开操作、重建顶帽操作等。其根本原理是通过腐蚀找到SE的模式,然后迭代膨胀或者迭代顶帽操作直到图像收敛。
代码
- #include <cv.h>
- #include <highgui.h>
- #include <stdio.h>
- #define TOFINDMAX 0
- #define TOFINDMIN 1
- #define isSIZEEQU(x,y) (((x)->width)==((y)->width)&&((x)->height)==((y)->height))
- struct position{
- int x;
- int y;
- };
- typedef struct position Position;
- //判断结构元是否平滑
- int isSmooth(IplImage *src){
- int width=src->width;
- int height=src->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++){
- int v=cvGetReal2D(src,j,i);
- if(v!=255.0&&v!=0.0)
- return 0;
- }
- return 1;
- }
- //判断两幅图像是否相等
- int isEqu(IplImage *src1,IplImage *src2){
- if(!isSIZEEQU(src1, src2))
- return 0;
- for(int i=0;i<src1->width;i++)
- for(int j=0;j<src1->height;j++){
- double v1=cvGetReal2D(src1, j, i);
- double v2=cvGetReal2D(src2, j, i);
- if(v1!=v2)
- return 0;
- }
- return 1;
- }
- //将图像全部设置为1
- void One(IplImage *src){
- int width=src->width;
- int height=src->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++)
- cvSetReal2D(src, j, i, 255.0);
- }
- //位移,如果非平滑SE将加上sevalue,即对应的灰度值
- void Translation(IplImage *src ,IplImage *dst,double SEvalue,Position *d,int istoFindMin){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- int srcwidth=src->width;
- int srcheight=src->height;
- int dstwidth=dst->width;
- int dstheight=dst->height;
- if(istoFindMin)
- One(temp);
- else
- cvZero(temp);
- for(int i=0;i<srcwidth;i++){
- for(int j=0;j<srcheight;j++){
- int target_x=i+d->x;
- int target_y=j+d->y;
- if(target_x>=0&&target_y>=0&&
- target_x<dstwidth&&target_y<dstheight){
- double value=cvGetReal2D(src, j, i)+SEvalue;
- value=(value>=255.0?255.0:value);
- cvSetReal2D(temp, target_y, target_x, value);
- }
- }
- }
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //找出两幅等大图像中同一位置中相对较大的像素值
- void MaxPix(IplImage *src1 ,IplImage *src2,IplImage *dst){
- if(!isSIZEEQU(src1, src2)||!isSIZEEQU(src1, dst)){
- printf("MaxPix wrong: src size not equ!\n");
- exit(1);
- }
- int width=src1->width;
- int height=src1->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++){
- double value1=cvGetReal2D(src1, j,i);
- double value2=cvGetReal2D(src2, j,i);
- value1>value2?cvSetReal2D(dst, j,i,value1):cvSetReal2D(dst, j, i, value2);
- }
- }
- //找出两幅等大图像中同一位置中相对较小的像素值
- void MinPix(IplImage *src1 ,IplImage *src2,IplImage *dst){
- if(!isSIZEEQU(src1, src2)||!isSIZEEQU(src1, dst)){
- printf("MaxPix wrong: src size not equ!\n");
- exit(1);
- }
- int width=src1->width;
- int height=src1->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++){
- double value1=cvGetReal2D(src1, j,i);
- double value2=cvGetReal2D(src2, j,i);
- value1<value2?cvSetReal2D(dst, j, i, value1):cvSetReal2D(dst, j, i, value2);
- }
- }
- //灰度图像膨胀
- void Dilate_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=center->x-i;
- d.y=center->y-j;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMAX);
- else
- Translation(temp, temp, value, &d,TOFINDMAX);
- MaxPix(temp, temp_last, temp_last);
- }
- }
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //灰度图像腐蚀
- void Erode_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=i-center->x;
- d.y=j-center->y;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMIN);
- else
- Translation(temp, temp, -1.0*value, &d,TOFINDMIN);
- MinPix(temp, temp_last, temp_last);
- }
- }
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //开操作
- void Open_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Erode_Gray(src, temp, se, center);
- Dilate_Gray(temp, temp, se, center);
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //闭操作
- void Close_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Dilate_Gray(src, temp, se, center);
- Erode_Gray(temp, temp, se, center);
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //灰度梯度形态学提取
- void Gard_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp_dilate=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_erode=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Dilate_Gray(src, temp_dilate, se, center);
- Erode_Gray(src, temp_erode, se, center);
- cvSub(temp_dilate, temp_erode, dst, NULL);
- cvReleaseImage(&temp_erode);
- cvReleaseImage(&temp_dilate);
- }
- //顶帽操作
- void TopHat(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Open_Gray(src, temp, se, center);
- cvSub( src,temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //底帽操作
- void BottomHat(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Close_Gray(src, temp, se, center);
- cvSub(temp,src, dst, NULL);
- cvReleaseImage(&temp);
- }
- //测地腐蚀
- void Erode_Gray_g(IplImage *src,IplImage *ground,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=i-center->x;
- d.y=j-center->y;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMIN);
- else
- Translation(temp, temp, -1.0*value, &d,TOFINDMIN);
- MinPix(temp, temp_last, temp_last);
- }
- }
- MaxPix(temp_last,ground,temp_last);
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //测地膨胀
- void Dilate_Gray_g(IplImage *src,IplImage *ground,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=center->x-i;
- d.y=center->y-j;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMAX);
- else
- Translation(temp, temp, value, &d,TOFINDMAX);
- MaxPix(temp, temp_last, temp_last);
- }
- }
- MinPix(temp_last, ground, temp_last);
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //重建开操作
- void Rebuild_Open(IplImage *src,IplImage *dst,IplImage *ground,IplImage *erodeSE,IplImage *dilateSE,int eroden){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- cvCopy(src, temp, NULL);
- for(int i=0;i<eroden;i++){
- Erode_Gray(temp, temp, erodeSE, NULL);
- }
- while(!isEqu(temp, temp_last)){
- cvCopy(temp, temp_last, NULL);
- Dilate_Gray_g(temp, ground, temp, dilateSE, NULL);
- }
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //重建闭操作,这段没测试
- void Rebuild_Close(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int dilaten){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- cvCopy(src, temp, NULL);
- for(int i=0;i<dilaten;i++){
- Dilate_Gray(temp, temp, dilateSE, NULL);
- }
- while(!isEqu(temp, temp_last)){
- cvCopy(temp, temp_last, NULL);
- Erode_Gray(temp, temp, erodeSE, NULL);
- MinPix(temp, ground, temp);
- }
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //重建顶帽操作
- void Rebuild_Tophat(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int eroden){
- Rebuild_Open(src,dst,ground,erodeSE,dilateSE,eroden);
- cvSub(src, dst, dst, NULL);
- }
- //重建底帽操作
- void Rebuild_Bottomhat(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int dilaten){
- Rebuild_Close(src,dst,ground,dilateSE,erodeSE,dilaten);
- cvSub(src, dst, dst, NULL);
- }
- int main(){
- return 1;
- }
结果图片:
以下结果原图为lena 512x512的图像产生:
腐蚀:
膨胀:
开操作:
闭操作:
顶帽操作:
底帽操作:
重建操作示意(冈萨雷斯 中文第三版 P437):
去除横向亮条:重建顶帽操作
重建开操作,去除纵向亮纹:
上图横向膨胀:
膨胀结果与重建顶帽操作的最小操作:
原图对比:
代码 [cpp] view plain copy #include <cv.h> #include <highgui.h> #include <stdio.h> #define TOFINDMAX 0 #define TOFINDMIN 1 #define isSIZEEQU(x,y) (((x)->width)==((y)->width)&&((x)->height)==((y)->height)) struct position{ int x; int y; }; typedef struct position Position; //判断结构元是否平滑 int isSmooth(IplImage *src){ int width=src->width; int height=src->height; for(int i=0;i<width;i++) for(int j=0;j<height;j++){ int v=cvGetReal2D(src,j,i); if(v!=255.0&&v!=0.0) return 0; } return 1; } //判断两幅图像是否相等 int isEqu(IplImage *src1,IplImage *src2){ if(!isSIZEEQU(src1, src2)) return 0; for(int i=0;i<src1->width;i++) for(int j=0;j<src1->height;j++){ double v1=cvGetReal2D(src1, j, i); double v2=cvGetReal2D(src2, j, i); if(v1!=v2) return 0; } return 1; } //将图像全部设置为1 void One(IplImage *src){ int width=src->width; int height=src->height; for(int i=0;i<width;i++) for(int j=0;j<height;j++) cvSetReal2D(src, j, i, 255.0); } //位移,如果非平滑SE将加上sevalue,即对应的灰度值 void Translation(IplImage *src ,IplImage *dst,double SEvalue,Position *d,int istoFindMin){ IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); int srcwidth=src->width; int srcheight=src->height; int dstwidth=dst->width; int dstheight=dst->height; if(istoFindMin) One(temp); else cvZero(temp); for(int i=0;i<srcwidth;i++){ for(int j=0;j<srcheight;j++){ int target_x=i+d->x; int target_y=j+d->y; if(target_x>=0&&target_y>=0&& target_x<dstwidth&&target_y<dstheight){ double value=cvGetReal2D(src, j, i)+SEvalue; value=(value>=255.0?255.0:value); cvSetReal2D(temp, target_y, target_x, value); } } } cvCopy(temp, dst, NULL); cvReleaseImage(&temp); } //找出两幅等大图像中同一位置中相对较大的像素值 void MaxPix(IplImage *src1 ,IplImage *src2,IplImage *dst){ if(!isSIZEEQU(src1, src2)||!isSIZEEQU(src1, dst)){ printf("MaxPix wrong: src size not equ!\n"); exit(1); } int width=src1->width; int height=src1->height; for(int i=0;i<width;i++) for(int j=0;j<height;j++){ double value1=cvGetReal2D(src1, j,i); double value2=cvGetReal2D(src2, j,i); value1>value2?cvSetReal2D(dst, j,i,value1):cvSetReal2D(dst, j, i, value2); } } //找出两幅等大图像中同一位置中相对较小的像素值 void MinPix(IplImage *src1 ,IplImage *src2,IplImage *dst){ if(!isSIZEEQU(src1, src2)||!isSIZEEQU(src1, dst)){ printf("MaxPix wrong: src size not equ!\n"); exit(1); } int width=src1->width; int height=src1->height; for(int i=0;i<width;i++) for(int j=0;j<height;j++){ double value1=cvGetReal2D(src1, j,i); double value2=cvGetReal2D(src2, j,i); value1<value2?cvSetReal2D(dst, j, i, value1):cvSetReal2D(dst, j, i, value2); } } //灰度图像膨胀 void Dilate_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){ int SEissmooth=isSmooth(se); IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Position centerde; centerde.x=se->width/2; centerde.y=se->height/2; if(center==NULL){ center=¢erde; } int sewidth=se->width; int seheight=se->height; cvCopy(src,temp_last,NULL); for(int i=0;i<sewidth;i++) for(int j=0;j<seheight;j++){ cvCopy(src,temp,NULL); double value=cvGetReal2D(se, j, i); if(value!=0.0){ Position d; d.x=center->x-i; d.y=center->y-j; if(SEissmooth) Translation(temp, temp, 0.0, &d,TOFINDMAX); else Translation(temp, temp, value, &d,TOFINDMAX); MaxPix(temp, temp_last, temp_last); } } cvCopy(temp_last, dst, NULL); cvReleaseImage(&temp); cvReleaseImage(&temp_last); } //灰度图像腐蚀 void Erode_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){ int SEissmooth=isSmooth(se); IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Position centerde; centerde.x=se->width/2; centerde.y=se->height/2; if(center==NULL){ center=¢erde; } int sewidth=se->width; int seheight=se->height; cvCopy(src,temp_last,NULL); for(int i=0;i<sewidth;i++) for(int j=0;j<seheight;j++){ cvCopy(src,temp,NULL); double value=cvGetReal2D(se, j, i); if(value!=0.0){ Position d; d.x=i-center->x; d.y=j-center->y; if(SEissmooth) Translation(temp, temp, 0.0, &d,TOFINDMIN); else Translation(temp, temp, -1.0*value, &d,TOFINDMIN); MinPix(temp, temp_last, temp_last); } } cvCopy(temp_last, dst, NULL); cvReleaseImage(&temp); cvReleaseImage(&temp_last); } //开操作 void Open_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){ IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Erode_Gray(src, temp, se, center); Dilate_Gray(temp, temp, se, center); cvCopy(temp, dst, NULL); cvReleaseImage(&temp); } //闭操作 void Close_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){ IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Dilate_Gray(src, temp, se, center); Erode_Gray(temp, temp, se, center); cvCopy(temp, dst, NULL); cvReleaseImage(&temp); } //灰度梯度形态学提取 void Gard_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){ IplImage *temp_dilate=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); IplImage *temp_erode=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Dilate_Gray(src, temp_dilate, se, center); Erode_Gray(src, temp_erode, se, center); cvSub(temp_dilate, temp_erode, dst, NULL); cvReleaseImage(&temp_erode); cvReleaseImage(&temp_dilate); } //顶帽操作 void TopHat(IplImage *src,IplImage *dst,IplImage *se,Position *center){ IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Open_Gray(src, temp, se, center); cvSub( src,temp, dst, NULL); cvReleaseImage(&temp); } //底帽操作 void BottomHat(IplImage *src,IplImage *dst,IplImage *se,Position *center){ IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Close_Gray(src, temp, se, center); cvSub(temp,src, dst, NULL); cvReleaseImage(&temp); } //测地腐蚀 void Erode_Gray_g(IplImage *src,IplImage *ground,IplImage *dst,IplImage *se,Position *center){ int SEissmooth=isSmooth(se); IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Position centerde; centerde.x=se->width/2; centerde.y=se->height/2; if(center==NULL){ center=¢erde; } int sewidth=se->width; int seheight=se->height; cvCopy(src,temp_last,NULL); for(int i=0;i<sewidth;i++) for(int j=0;j<seheight;j++){ cvCopy(src,temp,NULL); double value=cvGetReal2D(se, j, i); if(value!=0.0){ Position d; d.x=i-center->x; d.y=j-center->y; if(SEissmooth) Translation(temp, temp, 0.0, &d,TOFINDMIN); else Translation(temp, temp, -1.0*value, &d,TOFINDMIN); MinPix(temp, temp_last, temp_last); } } MaxPix(temp_last,ground,temp_last); cvCopy(temp_last, dst, NULL); cvReleaseImage(&temp); cvReleaseImage(&temp_last); } //测地膨胀 void Dilate_Gray_g(IplImage *src,IplImage *ground,IplImage *dst,IplImage *se,Position *center){ int SEissmooth=isSmooth(se); IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); Position centerde; centerde.x=se->width/2; centerde.y=se->height/2; if(center==NULL){ center=¢erde; } int sewidth=se->width; int seheight=se->height; cvCopy(src,temp_last,NULL); for(int i=0;i<sewidth;i++) for(int j=0;j<seheight;j++){ cvCopy(src,temp,NULL); double value=cvGetReal2D(se, j, i); if(value!=0.0){ Position d; d.x=center->x-i; d.y=center->y-j; if(SEissmooth) Translation(temp, temp, 0.0, &d,TOFINDMAX); else Translation(temp, temp, value, &d,TOFINDMAX); MaxPix(temp, temp_last, temp_last); } } MinPix(temp_last, ground, temp_last); cvCopy(temp_last, dst, NULL); cvReleaseImage(&temp); cvReleaseImage(&temp_last); } //重建开操作 void Rebuild_Open(IplImage *src,IplImage *dst,IplImage *ground,IplImage *erodeSE,IplImage *dilateSE,int eroden){ IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); cvCopy(src, temp, NULL); for(int i=0;i<eroden;i++){ Erode_Gray(temp, temp, erodeSE, NULL); } while(!isEqu(temp, temp_last)){ cvCopy(temp, temp_last, NULL); Dilate_Gray_g(temp, ground, temp, dilateSE, NULL); } cvCopy(temp, dst, NULL); cvReleaseImage(&temp); cvReleaseImage(&temp_last); } //重建闭操作,这段没测试 void Rebuild_Close(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int dilaten){ IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels); cvCopy(src, temp, NULL); for(int i=0;i<dilaten;i++){ Dilate_Gray(temp, temp, dilateSE, NULL); } while(!isEqu(temp, temp_last)){ cvCopy(temp, temp_last, NULL); Erode_Gray(temp, temp, erodeSE, NULL); MinPix(temp, ground, temp); } cvCopy(temp, dst, NULL); cvReleaseImage(&temp); cvReleaseImage(&temp_last); } //重建顶帽操作 void Rebuild_Tophat(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int eroden){ Rebuild_Open(src,dst,ground,erodeSE,dilateSE,eroden); cvSub(src, dst, dst, NULL); } //重建底帽操作 void Rebuild_Bottomhat(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int dilaten){ Rebuild_Close(src,dst,ground,dilateSE,erodeSE,dilaten); cvSub(src, dst, dst, NULL); } int main(){ return 1; } 结果图片: 以下结果原图为lena 512x512的图像产生: 腐蚀: 膨胀: 开操作: 闭操作: 顶帽操作: 底帽操作: 重建操作示意(冈萨雷斯 中文第三版 P437): 去除横向亮条:重建顶帽操作 重建开操作,去除纵向亮纹: 上图横向膨胀: 膨胀结果与重建顶帽操作的最小操作: 原图对比:
代码
- #include <cv.h>
- #include <highgui.h>
- #include <stdio.h>
- #define TOFINDMAX 0
- #define TOFINDMIN 1
- #define isSIZEEQU(x,y) (((x)->width)==((y)->width)&&((x)->height)==((y)->height))
- struct position{
- int x;
- int y;
- };
- typedef struct position Position;
- //判断结构元是否平滑
- int isSmooth(IplImage *src){
- int width=src->width;
- int height=src->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++){
- int v=cvGetReal2D(src,j,i);
- if(v!=255.0&&v!=0.0)
- return 0;
- }
- return 1;
- }
- //判断两幅图像是否相等
- int isEqu(IplImage *src1,IplImage *src2){
- if(!isSIZEEQU(src1, src2))
- return 0;
- for(int i=0;i<src1->width;i++)
- for(int j=0;j<src1->height;j++){
- double v1=cvGetReal2D(src1, j, i);
- double v2=cvGetReal2D(src2, j, i);
- if(v1!=v2)
- return 0;
- }
- return 1;
- }
- //将图像全部设置为1
- void One(IplImage *src){
- int width=src->width;
- int height=src->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++)
- cvSetReal2D(src, j, i, 255.0);
- }
- //位移,如果非平滑SE将加上sevalue,即对应的灰度值
- void Translation(IplImage *src ,IplImage *dst,double SEvalue,Position *d,int istoFindMin){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- int srcwidth=src->width;
- int srcheight=src->height;
- int dstwidth=dst->width;
- int dstheight=dst->height;
- if(istoFindMin)
- One(temp);
- else
- cvZero(temp);
- for(int i=0;i<srcwidth;i++){
- for(int j=0;j<srcheight;j++){
- int target_x=i+d->x;
- int target_y=j+d->y;
- if(target_x>=0&&target_y>=0&&
- target_x<dstwidth&&target_y<dstheight){
- double value=cvGetReal2D(src, j, i)+SEvalue;
- value=(value>=255.0?255.0:value);
- cvSetReal2D(temp, target_y, target_x, value);
- }
- }
- }
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //找出两幅等大图像中同一位置中相对较大的像素值
- void MaxPix(IplImage *src1 ,IplImage *src2,IplImage *dst){
- if(!isSIZEEQU(src1, src2)||!isSIZEEQU(src1, dst)){
- printf("MaxPix wrong: src size not equ!\n");
- exit(1);
- }
- int width=src1->width;
- int height=src1->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++){
- double value1=cvGetReal2D(src1, j,i);
- double value2=cvGetReal2D(src2, j,i);
- value1>value2?cvSetReal2D(dst, j,i,value1):cvSetReal2D(dst, j, i, value2);
- }
- }
- //找出两幅等大图像中同一位置中相对较小的像素值
- void MinPix(IplImage *src1 ,IplImage *src2,IplImage *dst){
- if(!isSIZEEQU(src1, src2)||!isSIZEEQU(src1, dst)){
- printf("MaxPix wrong: src size not equ!\n");
- exit(1);
- }
- int width=src1->width;
- int height=src1->height;
- for(int i=0;i<width;i++)
- for(int j=0;j<height;j++){
- double value1=cvGetReal2D(src1, j,i);
- double value2=cvGetReal2D(src2, j,i);
- value1<value2?cvSetReal2D(dst, j, i, value1):cvSetReal2D(dst, j, i, value2);
- }
- }
- //灰度图像膨胀
- void Dilate_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=center->x-i;
- d.y=center->y-j;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMAX);
- else
- Translation(temp, temp, value, &d,TOFINDMAX);
- MaxPix(temp, temp_last, temp_last);
- }
- }
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //灰度图像腐蚀
- void Erode_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=i-center->x;
- d.y=j-center->y;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMIN);
- else
- Translation(temp, temp, -1.0*value, &d,TOFINDMIN);
- MinPix(temp, temp_last, temp_last);
- }
- }
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //开操作
- void Open_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Erode_Gray(src, temp, se, center);
- Dilate_Gray(temp, temp, se, center);
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //闭操作
- void Close_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Dilate_Gray(src, temp, se, center);
- Erode_Gray(temp, temp, se, center);
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //灰度梯度形态学提取
- void Gard_Gray(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp_dilate=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_erode=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Dilate_Gray(src, temp_dilate, se, center);
- Erode_Gray(src, temp_erode, se, center);
- cvSub(temp_dilate, temp_erode, dst, NULL);
- cvReleaseImage(&temp_erode);
- cvReleaseImage(&temp_dilate);
- }
- //顶帽操作
- void TopHat(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Open_Gray(src, temp, se, center);
- cvSub( src,temp, dst, NULL);
- cvReleaseImage(&temp);
- }
- //底帽操作
- void BottomHat(IplImage *src,IplImage *dst,IplImage *se,Position *center){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Close_Gray(src, temp, se, center);
- cvSub(temp,src, dst, NULL);
- cvReleaseImage(&temp);
- }
- //测地腐蚀
- void Erode_Gray_g(IplImage *src,IplImage *ground,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=i-center->x;
- d.y=j-center->y;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMIN);
- else
- Translation(temp, temp, -1.0*value, &d,TOFINDMIN);
- MinPix(temp, temp_last, temp_last);
- }
- }
- MaxPix(temp_last,ground,temp_last);
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //测地膨胀
- void Dilate_Gray_g(IplImage *src,IplImage *ground,IplImage *dst,IplImage *se,Position *center){
- int SEissmooth=isSmooth(se);
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- Position centerde;
- centerde.x=se->width/2;
- centerde.y=se->height/2;
- if(center==NULL){
- center=¢erde;
- }
- int sewidth=se->width;
- int seheight=se->height;
- cvCopy(src,temp_last,NULL);
- for(int i=0;i<sewidth;i++)
- for(int j=0;j<seheight;j++){
- cvCopy(src,temp,NULL);
- double value=cvGetReal2D(se, j, i);
- if(value!=0.0){
- Position d;
- d.x=center->x-i;
- d.y=center->y-j;
- if(SEissmooth)
- Translation(temp, temp, 0.0, &d,TOFINDMAX);
- else
- Translation(temp, temp, value, &d,TOFINDMAX);
- MaxPix(temp, temp_last, temp_last);
- }
- }
- MinPix(temp_last, ground, temp_last);
- cvCopy(temp_last, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //重建开操作
- void Rebuild_Open(IplImage *src,IplImage *dst,IplImage *ground,IplImage *erodeSE,IplImage *dilateSE,int eroden){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- cvCopy(src, temp, NULL);
- for(int i=0;i<eroden;i++){
- Erode_Gray(temp, temp, erodeSE, NULL);
- }
- while(!isEqu(temp, temp_last)){
- cvCopy(temp, temp_last, NULL);
- Dilate_Gray_g(temp, ground, temp, dilateSE, NULL);
- }
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //重建闭操作,这段没测试
- void Rebuild_Close(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int dilaten){
- IplImage *temp=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- IplImage *temp_last=cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
- cvCopy(src, temp, NULL);
- for(int i=0;i<dilaten;i++){
- Dilate_Gray(temp, temp, dilateSE, NULL);
- }
- while(!isEqu(temp, temp_last)){
- cvCopy(temp, temp_last, NULL);
- Erode_Gray(temp, temp, erodeSE, NULL);
- MinPix(temp, ground, temp);
- }
- cvCopy(temp, dst, NULL);
- cvReleaseImage(&temp);
- cvReleaseImage(&temp_last);
- }
- //重建顶帽操作
- void Rebuild_Tophat(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int eroden){
- Rebuild_Open(src,dst,ground,erodeSE,dilateSE,eroden);
- cvSub(src, dst, dst, NULL);
- }
- //重建底帽操作
- void Rebuild_Bottomhat(IplImage *src,IplImage *dst,IplImage *ground,IplImage *dilateSE,IplImage *erodeSE,int dilaten){
- Rebuild_Close(src,dst,ground,dilateSE,erodeSE,dilaten);
- cvSub(src, dst, dst, NULL);
- }
- int main(){
- return 1;
- }
结果图片:
以下结果原图为lena 512x512的图像产生:
腐蚀:
膨胀:
开操作:
闭操作:
顶帽操作:
底帽操作:
重建操作示意(冈萨雷斯 中文第三版 P437):
去除横向亮条:重建顶帽操作
重建开操作,去除纵向亮纹:
上图横向膨胀:
膨胀结果与重建顶帽操作的最小操作:
原图对比:
闭操作是将跨度小于结构元的谷底填平