您的位置:首页 > 其它

区域填充_扫描线种子填充_广度优先算法种子填充

2009-11-26 16:48 155 查看
区域填充算法,代码原创,已经过测试。

包含:扫描线种子填充算法(可以填充凹形区域) 和广度优先搜索算法。

时间复杂度:N 矩阵的长宽 x1000 , 时间单位:毫秒






//________________________________

readme:

RegionFilling.h / .cpp 是填充算法实现文件
RegionFill.cpp 是演示文件。

//_______________________________



// RegionFill.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "RegionFilling.h"
#include <iostream>
#include "time.h"
#include "math.h"
using namespace std;

void usageDemo(int seedx, int seedy);

int _tmain(int argc, _TCHAR* argv[])
{

usageDemo(4,4);

return 1;

}

void usageDemo(int seedx, int seedy)
{
// step1. indicate a pointer(mat) to 2D matrix or image.
// step2. connect edge points. then we got the contour of the region
// step3. call scan line regionfilling (or bfs) function to fill region.
// step4. save matrix to a image




char **mat= new char*[30];
for(int i=0; i<30; i++)
{
mat[i] = new char[30];
for(int j=0; j<30; ++j)
{
mat[i][j]=0;
}
}
// step1: indicate a pointer(mat) to 2D matrix or image.
CRegionFilling rgnfil(mat,30,30,1,0,0);

int x[9];
int y[9];

x[0]=2;y[0]=2;
x[1]=2;y[1]=28;
x[2]=6;y[2]=15;
x[3]=10;y[3]=27;
x[4]=14;y[4]=15;
x[5]=18;y[5]=27;
x[6]=23;y[6]=15;
x[7]=28;y[7]=26;
x[8]=27;y[8]=4;

// step2. connect edge points. then we got the contour of the region
rgnfil.drawLine(x[0],y[0],x[8],y[8]);

for(int i=1; i<9; ++i)
{
rgnfil.drawLine(x[i-1],y[i-1],x[i],y[i]);
}



for(int i=0; i<30; ++i)
{
for(int j=0; j<30; ++j)
{
if(i==0 || j==0 ||i==30-1 || j==30-1)
mat[i][j]=1;
}
}

for(int i=0; i<30; ++i)
{
for(int j=0; j<30; ++j)
{
if(mat[i][j]==1)
{
cout<<"* ";
}
else
cout<<" ";

}
cout<<endl;

}
cout<<endl;

//step3. call scan line regionfilling function to fill region.
rgnfil.regionfill_scanning(seedx,seedy);

for(int i=0; i<30; ++i)
{
for(int j=0; j<30; ++j)
{
if(mat[i][j]==1)
{
cout<<"* ";
}
else
cout<<" ";

}
cout<<endl;
}
cout<<endl<<endl<<endl;

//step4. save matrix to a image
//code need to be added.

for(int del=0; del<30; ++del)
delete []mat[del];
delete []mat;

}





#pragma once
#include <stack>
using namespace std;

class CRegionFilling
{
public:
//pmat pointer to 2D matrix(image). 指向二维矩阵(图像)的指针
//Width: matrix width 矩阵宽度
//Height:matrix height 矩阵高度
//fillColor: fill color 填充颜色
//blankColor: indicate this point is not filled 空白的颜色
//connective_0for4_1for8: 4-connected using 0,8-connected using 1.连通性_0指定四连通_1指定8连通
CRegionFilling(char **pmat, int Width, int Height, int fillColor=1,int blankColor=0,int connective_0for4_1for8=0)
:mat(pmat),width(Width),height(Height),
fillclr(fillColor),blankclr(blankColor),
connectivity(connective_0for4_1for8)
{};
~CRegionFilling(void){};
private:
char **mat;
int width;
int height;
int fillclr;
int blankclr;
int connectivity;

struct cpixel
{
cpixel(void){};
cpixel(int X, int Y):x(X),y(Y){};
int x;
int y;
};
stack<cpixel> stc;



public:
//(x0,y0) start point of line, (x1,y1):end point of line.
// if(mat==NULL) return false, else return true.
bool drawLine(int x0, int y0, int x1, int y1);

//Time cost = O(N), N:height of matrix(image)
bool regionfill_scanning(int seedx, int seedy);

//Time cost = O(M*N), M*N means height*width of matrix(image)
bool regionfill_bfs(int seedx, int seedy);


private:
//this function is called by Breadth First Search (BFS) algorithm
//check the four neighbors of seed point,
//if( belongs to region && not filled) push to queue and brush it with fillclr.
//return value: if( belongs to region && not filled) return true,else return false.
inline bool checkNeighbor(int x, int y, int direction, cpixel& pt);

private:
//called by scan line algorithm
//fill scan line. (xr,yr) is the most right point of current scan line.
inline bool scanning(int xr,int yr);

//find new seeds and push to stack .
//return value: if found return true, else return false.
bool pushNewSeeds(int lx, int rx, int y);

};

bool CRegionFilling::checkNeighbor(int x, int y, int direction, cpixel& pt)
{

if(direction==0 && y-1>=0 && mat[y-1][x]==blankclr )
{
pt.x=x; pt.y=y-1;
return true;

}
else if(direction==2 && y+1<height && mat[y+1][x]==blankclr)
{
pt.x=x;pt.y=y+1;
return true;
}
else if(direction==1 && x+1<width && mat[y][x+1]==blankclr)
{
pt.x=x+1; pt.y=y;
return true;
}
else if(direction==3 && x-1>=0 && mat[y][x-1]==blankclr)
{
pt.x=x-1; pt.y=y;
return true;
}
else
return false;

}

bool CRegionFilling::scanning(int xr,int yr)
{
int x=xr;
while(x>=0 && mat[yr][x]==blankclr)
{
mat[yr][x]=fillclr;
--x;
}
return true;
}











#include "StdAfx.h"
#include "RegionFilling.h"
#include "math.h"
#include <stack>
#include <queue>

using namespace std;

bool CRegionFilling::regionfill_scanning(int seedx, int seedy)
{
int lx,rx;
int x=seedx;
int y=seedy;
cpixel seed(seedx,seedy);

//1 找到current行的右端点
while(x<width && mat[y][x]==blankclr)
++x;
--x; rx=x;
//2找到current行的左端点
x=seedx;
while(x>=0 && mat[y][x]==blankclr)
--x;
++x; lx=x;

stc.push(cpixel(rx,y));
while(!stc.empty())
{
seed = stc.top();
stc.pop();

rx=seed.x;
y=seed.y;

lx=rx;
while(lx>=0 && mat[y][lx] ==blankclr)
--lx;
++lx;
scanning(seed.x,seed.y);

if(y-1>=0)
pushNewSeeds(lx,rx,y-1);
if(y+1<width)
pushNewSeeds(lx,rx,y+1);

}

return true;
}





bool CRegionFilling::pushNewSeeds(int lx, int rx, int y)
{

if(y<0 || y>=height) return false;

//返回标识ret
//true;seeds or seed are found。
// false: seed not found.
bool ret=false;

//x是新的种子点的x坐标。
int x=rx;
int xa=lx,xb=rx;
while(lx<=rx)
{
x=rx;
//step1
//4.11 潜在的新种子点在rx之右,■是旧的种子点
// ●○○○○●
// ●●●■●
// rx
//x 1,2,3,4,5,6
if(mat[y][x]==blankclr)
{
//step1.找到新的种子点
while(x<width && mat[y][x]== blankclr)
++x; //x=6
--x; //x=5
stc.push(cpixel(x,y)); //new seed.x=5
ret=true;

//step2.找到扫描线的左端点
while(x>=0 && mat[y][x]==blankclr)
--x;
rx=x; //rx=1
// ●○○○○●
// ●●●■●
// rx
//x 1,2,3,4,5,6
}
//4.12潜在的新种子点在 rx之左。
// ●○○○○●●●
// ●●●●●●■●
// rx
else
{
--x;
while(x>=lx && mat[y][x]==fillclr)
--x;
if(x>=lx)
{
stc.push(cpixel(x,y));
ret=true;
//找到扫描线的左端点
while(x>=0 && mat[y][x]==blankclr)
--x;
rx=x;
}
}

if(lx>rx) continue;
// step1.
// ●○○○○●○○○○●○○○○●
// ●●●●●●●●●●●●●●●●
// lx rx
// 新的种子点位置 ★

// step2
// ●○○○○●○○○○●○○○○●
// ●●●●●●●●●●●●●●●●
// lx rx
// ★

// step3 进入第二次循环
// ●○○○○●○○○○●○○○○●
// ●●●●●●●●●●●●●●●●
// lx
// rx
// ★
//(lx>rx) 结束while

//从左边lx向右找,找到潜在的新种子点SEED_NEW,看 SEED_NEW =? SEED_R
//step2
x=lx;
if(mat[y][x]==blankclr)
{
//向右找
while(x<rx && mat[y][x]==blankclr)
++x;
--x;
stc.push(cpixel(x,y));
ret=true;
lx=x+2;
}
else
{
//仍然是向右找,找到扫描线的左端点停止,再继续找扫描线的右端点。
while(x<rx && mat[y][x]==fillclr)
++x;
//找扫描线的右端点。
if(x<rx)
{
while(x<rx && mat[y][x]==blankclr)
++x;
--x;
stc.push(cpixel(x,y));
ret=true;
}
lx=x+2;
}

}//while has another scan line to be found.

// 凹形区域的填充
// ●●●● ●●● ●●●●
// ●○○● ●○● ●○○●
// ●○○○● ●○○● ●○○○●
// ●○○○● ●○○● ●○○○●
// ●○○○○●○○○○●○○○○●
// ●○○○○○○○○○○○○○○●
// ●○○○○○○○○○○○○○○●
// ●●●●●●●●●●●●●●●●

return ret;



}//findSeed()



//广度优先搜索算法(Breadth First Search) -- 搜索填充点--入队列--填充
bool CRegionFilling::regionfill_bfs(int seedx, int seedy)
{
queue<cpixel> s;
s.push(cpixel(seedx,seedy));
register cpixel pt;
while(!s.empty())
{
pt=s.front();
s.pop();
register cpixel newpt;
//i=0-->3 表示 ↑ → ↓ ←
for(int i=0; i<4; ++i)
{
if( checkNeighbor(pt.x,pt.y,i,newpt))
{
s.push(newpt);
mat[newpt.y][newpt.x]=fillclr;
}
}

}

return true;
}

bool CRegionFilling::drawLine(const int x0, const int y0, const int x1, const int y1)
{
if(!mat) return false;
//temp variable x,y
int x,y;

//水平和竖直情况
if(x1==x0)
{
for(y=y0; y<=y1; ++y)
mat[y][x1]=fillclr;
return true;
}
if(y1==y0)
{
for(x=x0; x<=x1; ++x)
mat[y1][x]=fillclr;
return true;
}

//斜线 y = k*x + b
int dx=x1-x0;
int dy=y1-y0;
double k=dy/(double)dx;
double b=(x1*y0-x0*y1)/(double)(x1-x0);
if( abs(dx) >= abs(dy) )
{
int l,r,prey;
if(x0<x1) {l=x0;r=x1;prey=y0;}
else {l=x1,r=x0;prey=y1;}
for(x=l; x<=r; ++x)
{
y =(int) (k*x+b +0.5);
mat[y][x]=fillclr;
//code for 4-connective rule.
if(connectivity==0)
{
if(y!=prey)
{
mat[prey][x]=fillclr;
prey = y;
}

}

}
}
else
{
int prex;
int l,r;

if(y0<y1) {l=y0;r=y1;prex=x0;}
else {l=y1,r=y0;prex=x1;}

for(y=l; y<=r; ++y)
{
x=(int)((y-b)/k + 0.5);
mat[y][x]=fillclr;
//code for 4-connective rule.
if(connectivity==0)
{
if(x!=prex)
{
mat[y][prex]=fillclr;
prex = x;
}
}

}
}

return true;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: