您的位置:首页 > 其它

滴水算法小结

2016-07-05 00:53 1861 查看

滴水算法概述

滴水算法是一种用于分割手写粘连字符的算法,与以往的直线式地分割不同 ,它模拟水滴的滚动,通过水滴的滚动路径来分割字符,可以解决直线切割造成的过分分割问题。以下将分别叙述:

传统滴水算法

惯性滴水算法

大水滴惯性滴水算法

1. 传统滴水算法

滴水算法滴落规则

滴落规则如图[1-1]所示



图[1-1]滴水算法滴落规则

水滴周围像素编号如图[1-2]所示



图[1-2]水滴周围像素编号

图[1-2]中N0表示当前的水滴当前的位置,水滴下一步的低落位置由它下方的三个像素点和它左右两个像素点,共五个像素点决定。图[1-2]显示了水滴下一滴落位置的选择规则,其中w表示白点,b表示黑点,* 表示即有可能是白点也有可能是黑点。

传统滴水算法的数学模型



图[1-3]图片的坐标系

设要分割的图片是II是一张二值图,它的尺寸是N*MN是图片的高,M是图片的宽,建立坐标系如图[1-3]所示。设水滴的当前坐标为(xi,yi),水滴的滴落路径为T,则T(xi+1,yi+1)=f(xi,yi,Wi),(i=0,1,2,3,4...)。其中(xi+1,yi+1)表示水滴下一步滴落点的坐标,Wi则是水滴在当前位置上重力势能的衡量。Wi的值由式[1_1]决定

Wi=⎧⎩⎨4maxj=15ZjWjΣ = 0 or 15其他

式[1-1]

其中,Σ=∑5j=1ZjWj,Zj表示Nj点的像素值,0表示黑点,1表示白点。Wj表示Nj点被选为下一滴落点的权重大小,Wj=6−j。那么,建立如下关系:

T(xi+1,yi+1)=f(xi,yi,Wi)=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪(xi,yi−1)(xi,yi+1)(xi+1,yi+1)(xi+1,yi)(xi+1,yi−1)Wi=1Wi=2Wi=3Wi=4Wi=5

式[1-2]

传统滴水算法流程描述

确定水滴起始点

计算Σ的值

根据Σ的值,代入式[1-1]计算Wi的值

由Wi的值根据式[1-2]计算(xi+1,yi+1)

判断(xi+1,yi+1)到达图片下边界时算法结束,否则转到2步

补充 : 计算水滴的起点,选择第一个满足像素分布情况为(…0*1…10)的白色像素点(*)为起始点。其中0表示黑色像素点,1表示白色像素点。



图[1-4]应用DFA进行初始点确定

传统滴水算法 c++ 代码实现

#define OutputMat           cv::Mat &

#define InputMat            cv::Mat &

#define OutputMatArray      std::list<cv::Mat> &

#define InputMatArray       std::list<cv::Mat> &

int DropFallAlgo(InputMat inImg, OutputMatArray outImgArray) {

// 判断是不是单通道图
if (inImg.channels() != 1)
return -1;
int nl = inImg.rows;
// 图像的列数
int nc = inImg.cols;

// 确定始点 用于滴水算法的开始位置

cv::Point beginePoint(0,0);

// DFA
int BIA = 0;
for (int i = 0; i < nl; i++)
{
if (inImg.ptr<uchar>(i)[0] == COLOR_BLACK)
{
BIA = 2;
}
else
{
BIA = 1;
}

for (int j = 0; j < nc; j++)
{
switch (BIA)
{
case 1 :
if (inImg.ptr<uchar>(i)[j] == COLOR_BLACK)
{
BIA++;
}
break;
case 2 :
if (inImg.ptr<uchar>(i)[j] == COLOR_WHITE)
{
beginePoint.x = i;
beginePoint.y = j;
BIA++;
}
break;
case 3 :
if (inImg.ptr<uchar>(i)[j] == COLOR_BLACK)
{
BIA++;
}
break;
case 4 :
break;
default:
break;
}

if (BIA == 4)
{
std::cout << beginePoint.x << "  " << beginePoint.y << '\n';
break;
}
}

if (BIA == 4)
{
break;
}
}

// 执行滴水算法
std::list<cv::Point> pointList;

pointList.push_back(beginePoint);

// 只遍历行
for (int i = 0; i < nl-1; i++)
{
int x = pointList.back().x, y = pointList.back().y;
if (x == nl -1)
{
break;
}
int Sigma = 0,wi = 0, m = 1,Max = INT_MIN;;

// 求解Sigma
for (int j = 0; j < 2; j++)
{
for (int k = -1; k < 2; k++)
{
if (j!=0 || k!=0)
{
int tPix = 0;
if (inImg.ptr<uchar>(x+j)[y+k] == COLOR_BLACK)
{
tPix = 0;
}
else
{
tPix = 1;
}
int tSigma = tPix * (m++-j*k*2);

if (tSigma > Max)
{
Max = tSigma;
}
Sigma += tSigma;
}
}
}

// 根据sigma 计算wi
if (Sigma == 15 || Sigma == 0) {
wi = 4;
}
else
{
wi = Max;
}

cv::Point tPoint;
switch (wi)
{
case 1:
tPoint.x = x;
tPoint.y = y-1;

break;
case 2:
tPoint.x = x;
tPoint.y = y + 1;
break;
case 3:
tPoint.x = x + 1;
tPoint.y = y + 1;
break;
case 4:
tPoint.x = x + 1;
tPoint.y = y ;
break;
case 5:
tPoint.x = x + 1;
tPoint.y = y - 1;
break;
default:
break;
}

pointList.push_back(tPoint);
}

std::list<cv::Point> ::iterator iter = pointList.begin();

while (iter != pointList.end())
{
std::cout << iter->x << '\t' << iter->y << '\n';
iter++;

inImg.ptr<uchar>(iter->x)[iter->y] = 255;
}

return 0;
}


代码说明 : 应用C++ 和 opencv3.0编写,以上仅仅为实现滴水算法的一个函数

传统滴水算法缺点分析及改进方向
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: