博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
种子填充算法描述及C++代码实现
阅读量:6616 次
发布时间:2019-06-25

本文共 9296 字,大约阅读时间需要 30 分钟。

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

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

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

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

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

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

1 //视频处理测试算法,种子填充算法,扫描线算法,二值图像  2 //用栈会保存,这里把栈换成链表了,下面有栈注释掉代码  3 //20140911  4 #include 
5 #include "cv.h" 6 #include "highgui.h" 7 #include
8 #include
9 #include
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"<
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
stk;//stl栈103 std::list
lst;//stl链表104 cvZero(dst);105 //IplImage *tempimage=cvCreateImage(cvGetSize(src),8,1);//创建一个临时数据,保存源图像数据到目标过度数据106 int t_i;//每次种子的位置107 int t_j;108 //cvZero(tempimage);//临时数据初始化,清0109 for (int i=1;i
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
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<
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 else157 {158 //std::list
().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 
3 #include "cv.h" 4 #include "highgui.h" 5 #include
6 #include
7 #include
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"<
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
stk;//stl栈 68 std::list
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
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
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 else109 {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 else127 {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
imageData[(t_i-1)*width+up_yLeft]=0;//二值图像152 }153 else154 {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
imageData[(t_i+1)*width+down_yLeft]&&down_yLeft
imageData[(t_i+1)*width+down_yLeft]=0;//二值图像192 }193 else194 {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
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 else234 {235 //std::list
().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 }

效果如下图:

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

 

转载于:https://www.cnblogs.com/zCoderJoy/p/3972361.html

你可能感兴趣的文章
linux系统串口使用,linux使用串口说明
查看>>
linux实验串口网络通信编程仪,Linux串口通信编程
查看>>
linux下怎么绑定arp,LINUX 下进行arp 绑定.doc
查看>>
sys_brk分析 linux1.2.0版本,linux内存管理之sys_brk实现分析(续)
查看>>
c语言14年春机考答案,计算机二级《C语言》机考试题与答案
查看>>
c语言括号匹配问题不用栈,括号匹配问题(不用栈,用数组)
查看>>
c语言指针课堂教学设计,“C语言程序设计”课程指针的教学设计
查看>>
gradle是否可以编译c语言,使用CPP插件在gradle中编译C++代码
查看>>
c语言程实训报告,C语言程设计工程实训报告.doc
查看>>
C语言高斯消元课程设计报告,c高斯消元法解方程-课程设计报告.doc
查看>>
三坐标DMIS语言是C语言吗,三坐标测量软件PC-DMIS常见技巧
查看>>
空间域图像增强c语言,OpenCV 图像增强(空间域)
查看>>
android 窗口分割线,android RecyclerView 万能分隔线
查看>>
电脑android模拟器下载地址,仙域奇缘电脑版怎么下载 安卓模拟器电脑版下载地址...
查看>>
Android WebView 总结,android webview总结
查看>>
android mac 照片恢复,相片恢复?误删的手机照片简单的找回方法来了!
查看>>
html中的text标签怎么设置自动换行,innerHTML中标签可以换行的方法汇总
查看>>
html5性能在线测试,HTML5性能测试
查看>>
美团Android三面,美团面经后端一面挂,安卓三面(实习)
查看>>
android环境搭建注意事项,android studio教程及android环境搭建
查看>>