项目需要看了种子填充算法,改进了算法主要去除面积小的部分。种子填充算法分为两种,简单的和基于扫描线的方法,简单的算法如下描述(笔者针对的是二值图像):

(1)从上到下,从左到有,依次扫描每个像素;

(2)遇到一个非零数值压栈,并置原图像像素点值为0,面积初始化为1;否则,处理完毕。

(3)对栈非空查找,如果非空弹出栈顶,检测4领域或8领域,如果非空压栈,并置原图像像素点为0,标示不在处理此点,面积加1;如果为空,停止;

(4)判断面积是否大于给定阈值,小于的删掉,大于的把得到的所有像素点保存到目标图像上去,继续扫描像素,转2。

这里我用c++实现,开始用的stl栈,运行一段时间会有中断,之后换成链表可以了,代码共享如下,可以运行,图片使用二值,有需要的可以留下邮箱,一起研究:

  1 //视频处理测试算法,种子填充算法,扫描线算法,二值图像
  2 //用栈会保存,这里把栈换成链表了,下面有栈注释掉代码
  3 //20140911
  4 #include <iostream>
  5 #include "cv.h"
  6 #include "highgui.h"
  7 #include <stack>
  8 #include <list>
  9 #include <string>
 10 
 11 using namespace std;
 12 int ScanLine_SeedFillingAlgo(IplImage *src,IplImage *dst,int MinCutNumb);//原图像和目标图像不要是同一副图像
 13 int main()
 14 {
 15     IplImage *ipl_origin;
 16     IplImage *ipl_target;
 17     string fname = "D:/无腐蚀膨胀/Fight1save";
 18     cvNamedWindow("原始图片");
 19     cvNamedWindow("处理后图片");
 20     for (int k=0;k<110;k++)
 21     {
 22         string filename="";
 23         char tmp[20];
 24         _itoa_s(k,tmp,20,10);
 25         filename+=tmp;
 26         filename+=".bmp";
 27         filename=fname+filename;
 28         ipl_origin=cvLoadImage(filename.c_str(),-1);
 29         ipl_target=cvCreateImage(cvGetSize(ipl_origin),8,1);//cvCloneImage(ipl_origin);
 30 
 31         cvZero(ipl_target);
 32         cvShowImage("原始图片",ipl_origin);
 33         int s=clock();
 34         ScanLine_SeedFillingAlgo(ipl_origin,ipl_target,125);
 35         int e=clock();
 36         std::cout<<"\n"<<e-s;
 37         cvShowImage("处理后图片",ipl_target);
 38         cvWaitKey(1);
 39         cvReleaseImage(&ipl_origin);
 40         cvReleaseImage(&ipl_target);
 41     }
 42 
 43 
 44     cvWaitKey(0);
 45 
 46     cvDestroyWindow("原始图片");
 47     cvDestroyWindow("处理后图片");
 48 
 49 }
 50 //MinCutNumb代表剔除面积小于MinCutNumb的值;
 51 //返回找到目标数
 52 int ScanLine_SeedFillingAlgo(IplImage *src,IplImage *dst,int MinCutNumb)
 53 {
 54     int i, j, k;
 55     for ( i = 0; i < 3; i++ )        //上下两行
 56     {
 57         unsigned char * t_pPos = (unsigned char *) ( &src->imageData[ i * src->widthStep ] );
 58 
 59         for ( j = 0; j < src->widthStep; j++ )
 60         {
 61             * t_pPos = (unsigned char)0;
 62             t_pPos++;
 63         }
 64     }
 65 
 66     for ( i = ( src->height - 3 ); i < src->height; i++ )        //上下两行
 67     {
 68         unsigned char * t_pPos = (unsigned char *) ( &src->imageData[ i * src->widthStep ] );
 69 
 70         for ( j = 0; j < src->widthStep; j++ )
 71         {
 72             * t_pPos = (unsigned char)0;
 73             t_pPos++;
 74         }
 75     }
 76 
 77     for ( i = 0; i < src->height; i++ )    //左右两边
 78     {
 79         unsigned char * t_pPos = (unsigned char *) ( &src->imageData[ i * src->widthStep ] );
 80 
 81         for ( j = 0; j < 3; j++ )
 82         {
 83             * t_pPos = (unsigned char)0;
 84             t_pPos++;
 85         }
 86 
 87         t_pPos = (unsigned char *) ( &src->imageData[ i * src->widthStep + src->widthStep - 3 ] );
 88 
 89         for ( j = ( src->widthStep - 3 ); j < src->widthStep; j++ )
 90         {
 91             * t_pPos = (unsigned char)0;
 92             t_pPos++;
 93         }
 94     }
 95     int width = src->width;
 96     int height = src->height;
 97     int targetSumNumb=0;
 98     int area;
 99     CvPoint direction_4[]={{-1, 0}, {0, 1}, {1, 0}, {0, -1}};//上右下左
100     //CvPoint direction_8[] = { {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1} };//顺时针
101     int n_Count=sizeof(direction_4)/sizeof(CvPoint);//遍历方向个数
102     std::list<CvPoint> stk;//stl栈
103     std::list<CvPoint> lst;//stl链表
104     cvZero(dst);
105     //IplImage *tempimage=cvCreateImage(cvGetSize(src),8,1);//创建一个临时数据,保存源图像数据到目标过度数据
106     int t_i;//每次种子的位置
107     int t_j;
108     //cvZero(tempimage);//临时数据初始化,清0
109     for (int i=1;i<height-1;i++)
110     {
111         for (int j=1;j<width-1;j++)
112         {
113             //int s=clock();
114 
115             //
116             if (src->imageData[i*width+j])
117             {
118                 targetSumNumb++;
119                 stk.push_back(cvPoint(i,j));//栈换成链表
120                 lst.push_back(cvPoint(i,j));
121                 src->imageData[i*width+j]=0;//二值图像
122                 //tempimage->imageData[i*width+j]=255;
123                 area=1;                
124                 while (!stk.empty())
125                 {
126                     CvPoint seed=stk.back();//弹出头部
127                     stk.pop_back();
128                     t_i=seed.x;
129                     t_j=seed.y;
130                     if (t_i<=0||t_i>=height||t_j<=0||t_j>=width)
131                         continue;
132                     for (int ii=0;ii<n_Count;ii++)//扫描各个方向
133                     {
134                         if (src->imageData[(t_i+direction_4[ii].x)*width+t_j+direction_4[ii].y])
135                         {
136                             area++;
137                             stk.push_back(cvPoint(t_i+direction_4[ii].x,t_j+direction_4[ii].y));
138                             lst.push_back(cvPoint(t_i+direction_4[ii].x,t_j+direction_4[ii].y));
139                             src->imageData[(t_i+direction_4[ii].x)*width+t_j+direction_4[ii].y]=0;//二值图像
140                             //tempimage->imageData[(t_i+direction_4[ii].x)*width+t_j+direction_4[ii].y]=255;
141                         }
142                     }
143                 }
144                 //int e=clock();
145                 //std::cout<<e-s;
146                 if (area>MinCutNumb)
147                 {
148                     //cvOr(dst,tempimage,dst);
149                     while (!lst.empty())
150                     {
151                         CvPoint tmpPt=lst.front();
152                         lst.pop_front();
153                         dst->imageData[tmpPt.x*width+tmpPt.y]=255;
154                     }
155                 }
156                 else
157                 {
158                     //std::list<CvPoint>().swap(lst);
159                     //while (!lst.empty()) lst.pop_back();
160                     //lst.resize(0);
161                     //lst.
162                     lst.clear();
163                 }
164 
165             }//判断是否入栈
166             //CvPoint 
167 
168         }
169     }
170     //cvReleaseImage(&tempimage);
171     return targetSumNumb;
172 }

图片处理效果:

基于扫描线的算法,描述如下(也是针对二值图像编程的):

(1) 初始化一个空的栈用于存放种子点,将种子点(x, y)入栈;

(2) 判断栈是否为空,如果栈为空则结束算法,否则取出栈顶元素作为当前扫描线的种子点(x, y),y是当前的扫描线;

(3) 从种子点(x, y)出发,沿当前扫描线向左、右两个方向填充,直到边界。分别标记区段的左、右端点坐标为xLeft和xRight;

(4) 分别检查与当前扫描线相邻的y - 1和y + 1两条扫描线在区间[xLeft, xRight]中的像素,从xLeft开始向xRight方向搜索,若存在非边界且未填充的像素点,则找出这些相邻的像素点中最右边的一个,并将其作为种子点压入栈中,然后返回第(2)步。

也是用的c++实现,代码如下:

  1 //视频处理测试算法,种子填充算法,扫描线算法,二值图像
  2 #include <iostream>
  3 #include "cv.h"
  4 #include "highgui.h"
  5 #include <stack>
  6 #include <list>
  7 #include <string>
  8 
  9 using namespace std;
 10 int ScanLine_SeedFillingAlgoE(IplImage *src,IplImage *dst,int MinCutNumb);//原图像和目标图像不要是同一副图像
 11 int main()
 12 {
 13     IplImage *ipl_origin;
 14     IplImage *ipl_target;
 15     string fname = "C:/Users/zcx/Desktop/打架斗殴测试图片/第四次无腐蚀膨胀/Fight1save";
 16     cvNamedWindow("原始图片");
 17     cvNamedWindow("处理后图片");
 18     for (int k=0;k<246;k++)
 19     {
 20         string filename="";
 21         char tmp[20];
 22         _itoa_s(k,tmp,20,10);
 23         filename+=tmp;
 24         filename+=".bmp";
 25         filename=fname+filename;
 26         ipl_origin=cvLoadImage(filename.c_str(),-1);
 27         //ipl_target=cvCreateImage(cvGetSize(ipl_origin),8,1);//cvCloneImage(ipl_origin);
 28 
 29         //cvZero(ipl_target);
 30         cvShowImage("原始图片",ipl_origin);
 31         int s=clock();
 32         ScanLine_SeedFillingAlgoE(ipl_origin,ipl_origin,125);
 33         int e=clock();
 34         std::cout<<"\n"<<e-s;
 35         cvShowImage("处理后图片",ipl_origin);
 36         cvWaitKey(1);
 37         
 38     }
 39 
 40 
 41 
 42 
 43 
 44 
 45     cvWaitKey(0);
 46     cvReleaseImage(&ipl_origin);
 47     //cvReleaseImage(&ipl_target);
 48     cvDestroyWindow("原始图片");
 49     cvDestroyWindow("处理后图片");
 50 
 51 }
 52 //MinCutNumb代表剔除面积小于MinCutNumb的值;
 53 //返回找到目标数
 54 int ScanLine_SeedFillingAlgoE(IplImage *src,IplImage *dst,int MinCutNumb)
 55 {
 56     int width = src->width;
 57     int height = src->height;
 58     int targetSumNumb=0;//目标数
 59     int area;//区域面积
 60     int rcount=0,lcount=0;//向左向右计算像素个数
 61     int yLeft,yRight;//左右像素坐标
 62     //IplImage *src=cvCreateImage(cvGetSize(p_src),8,1);//cvCloneImage(p_src);
 63     //cvCopy(p_src,src);
 64     CvPoint direction_4[]={{-1, 0}, {0, 1}, {1, 0}, {0, -1}};//上右下左
 65     //CvPoint direction_8[] = { {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1} };//顺时针
 66     int n_Count=sizeof(direction_4)/sizeof(CvPoint);//遍历方向个数
 67     std::list<CvPoint> stk;//stl栈
 68     std::list<CvPoint> lst;//stl链表
 69     
 70     IplImage *tempimage=cvCreateImage(cvGetSize(src),8,1);//创建一个临时数据,保存源图像数据到目标过度数据
 71     int t_i,t_j;//每次种子的位置
 72     int rt_j,lt_j;//左右搜索
 73     cvZero(tempimage);//临时数据初始化,清0
 74     for (int i=1;i<height-1;i++)
 75     {
 76         for (int j=1;j<width-1;j++)
 77         {
 78             //int s=clock();
 79 
 80             //
 81             if (src->imageData[i*width+j])
 82             {
 83                 targetSumNumb++;
 84                 stk.push_back(cvPoint(i,j));//栈换成链表
 85                 lst.push_back(cvPoint(i,j));
 86                 src->imageData[i*width+j]=0;//二值图像
 87                 //tempimage->imageData[i*width+j]=255;
 88                 area=1;                
 89                 while (!stk.empty())
 90                 {
 91                     CvPoint seed=stk.back();//弹出头部
 92                     stk.pop_back();
 93                     t_i=seed.x;
 94                     rt_j=lt_j=t_j=seed.y;
 95                     if (t_i<=0||t_i>=height)//上下扫描界限
 96                         continue;
 97                     //向右扫描
 98                     rcount=0,lcount=0;
 99                     while (rt_j<width)
100                     {
101                         //++t_j;
102                         if (src->imageData[t_i*width+(++rt_j)])
103                         {
104                             rcount++;                        
105                             lst.push_back(cvPoint(t_i,rt_j));
106                             src->imageData[t_i*width+rt_j]=0;//二值图像
107                         }
108                         else
109                         {
110                             break;
111                         }
112                     }
113                     area+=rcount;
114                     yRight=t_j+rcount;//右边坐标
115                     //向左扫描
116                     while (lt_j>0)
117                     {
118                         //++t_j;
119                         if (src->imageData[t_i*width+(--lt_j)])
120                         {
121                             lcount++;                        
122                             lst.push_back(cvPoint(t_i,lt_j));
123 
124                             src->imageData[t_i*width+lt_j]=0;//二值图像
125                         }
126                         else
127                         {
128                             break;
129                         }
130                     }
131                     area+=lcount;
132                     yLeft=t_j-lcount;//左边坐标
133                     //上一行搜索入栈点
134                     int up_yLeft=yLeft,up_yRight=yRight;
135                     bool up_findNewSeed = false;//判断是否找到种子点
136                     while(up_yLeft<=up_yRight)
137                     {
138                         up_findNewSeed = false;
139                         while(src->imageData[(t_i-1)*width+up_yLeft]&&up_yLeft<width)
140                         {
141                             up_findNewSeed=true;
142                             up_yLeft++;
143                         }
144                     
145                         if (up_findNewSeed)
146                         {
147                             if (up_yLeft==up_yRight)
148                             {
149                                 stk.push_back(cvPoint(t_i-1,up_yLeft));
150                                 lst.push_back(cvPoint(t_i-1,up_yLeft));
151                                 src->imageData[(t_i-1)*width+up_yLeft]=0;//二值图像
152                             }
153                             else
154                             {
155                                 stk.push_back(cvPoint(t_i-1,up_yLeft-1));
156                                 lst.push_back(cvPoint(t_i-1,up_yLeft-1));
157                                 src->imageData[(t_i-1)*width+up_yLeft-1]=0;//二值图像
158                             }
159                             up_findNewSeed=false;
160                         }
161                         int itemp=up_yLeft;
162                         while (!src->imageData[(t_i-1)*width+up_yLeft]&&up_yLeft<up_yRight)
163                         {
164                             up_yLeft++;
165                         }
166                         if (itemp==up_yLeft)
167                         {
168                             up_yLeft++;
169                         }
170                     }
171                     
172                     //下一行搜索入栈点
173                     int down_yLeft=yLeft,down_yRight=yRight;
174                     bool down_findNewSeed = false;//判断是否找到种子点
175                     while(down_yLeft<=down_yRight)
176                     {
177                         down_findNewSeed = false;
178                         while(src->imageData[(t_i+1)*width+down_yLeft]&&down_yLeft<width)
179                         {
180                             down_findNewSeed=true;
181                             down_yLeft++;
182                         }
183                         
184                         if (down_findNewSeed)
185                         {
186                             if (down_yLeft==down_yRight)
187                             {
188                                 ++area;
189                                 stk.push_back(cvPoint(t_i+1,down_yLeft));
190                                 lst.push_back(cvPoint(t_i+1,down_yLeft));
191                                 src->imageData[(t_i+1)*width+down_yLeft]=0;//二值图像
192                             }
193                             else
194                             {
195                                 ++area;
196                                 stk.push_back(cvPoint(t_i+1,down_yLeft-1));
197                                 lst.push_back(cvPoint(t_i+1,down_yLeft-1));
198                                 src->imageData[(t_i+1)*width+down_yLeft-1]=0;//二值图像
199                             }
200                             down_findNewSeed=false;
201                         }
202                         int itemp=down_yLeft;
203                         while (!src->imageData[(t_i+1)*width+down_yLeft]&&down_yLeft<down_yRight)
204                         {
205                             down_yLeft++;
206                         }
207                         if (itemp==down_yLeft)
208                         {
209                             down_yLeft++;
210                         }
211                         
212                     }
213                     
214 
215 
216 
217 
218 
219                     
220                 }
221                 //int e=clock();
222                 //std::cout<<e-s;
223                 if (area>MinCutNumb)
224                 {
225                     //cvOr(dst,tempimage,dst);
226                     while (!lst.empty())
227                     {
228                         CvPoint tmpPt=lst.front();
229                         lst.pop_front();
230                         tempimage->imageData[tmpPt.x*width+tmpPt.y]=255;
231                     }
232                 }
233                 else
234                 {
235                     //std::list<CvPoint>().swap(lst);
236                     //while (!lst.empty()) lst.pop_back();
237                     //lst.resize(0);
238                     //lst.
239                     lst.clear();
240                 }
241 
242             }//判断是否入栈
243             //CvPoint 
244 
245         }
246     }
247     //cvZero(dst);
248     cvCopy(tempimage,dst);
249     cvReleaseImage(&tempimage);
250     return targetSumNumb;
251 }

效果如下图:

小结:去除小面积效果还好,这里实现两种算法的时间优化并不是很明显,自己编程实现效率并不是很高,仅供参考,有园友写的比较好的代码可以分享一下,大家互相学习。

 

posted on 2014-09-15 10:43  zCoderJoy  阅读(13687)  评论(0编辑  收藏  举报