滴水算法小结
来源:互联网 发布:安顺行知高中图片 编辑:程序博客网 时间:2024/06/10 14:44
滴水算法概述
滴水算法是一种用于分割手写粘连字符的算法,与以往的直线式地分割不同 ,它模拟水滴的滚动,通过水滴的滚动路径来分割字符,可以解决直线切割造成的过分分割问题。以下将分别叙述:
- 传统滴水算法
- 惯性滴水算法
- 大水滴惯性滴水算法
1. 传统滴水算法
滴水算法滴落规则
滴落规则如图[1-1]所示
图[1-1]滴水算法滴落规则
水滴周围像素编号如图[1-2]所示
图[1-2]水滴周围像素编号
图[1-2]中N0表示当前的水滴当前的位置,水滴下一步的低落位置由它下方的三个像素点和它左右两个像素点,共五个像素点决定。图[1-2]显示了水滴下一滴落位置的选择规则,其中w表示白点,b表示黑点,* 表示即有可能是白点也有可能是黑点。传统滴水算法的数学模型
图[1-3]图片的坐标系
设要分割的图片是I,I是一张二值图,它的尺寸是N*M,N是图片的高,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);// DFAint 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编写,以上仅仅为实现滴水算法的一个函数
传统滴水算法缺点分析及改进方向
1 0
- 滴水算法小结
- 一滴水
- 滴水冰冻
- 滴水冰冻
- 滴水鲸
- 基于惯性大水滴滴水算法和支持向量机的粘连字符验证码识别
- 基于惯性大水滴滴水算法和支持向量机的验证码识别
- 算法小结
- 算法小结
- 算法小结
- 算法小结
- 黄河中的一滴水
- 一滴水[Blog synchronous]
- 滴水藏海
- 滴水的开始
- 直播-滴水藏海
- 排序算法小结
- 排序算法小结
- android保存ArrayList到本地并显示(重复的问题已解决)
- iOS App 性能备忘
- JSON格式
- 机器学习之感知器学习算法
- AlertDialog
- 滴水算法小结
- 程序分析常见的WYSINWYX现象-What You See Is Not What You eXecute
- 读后感:一念永恒
- 慢查询slowlog记录日志问题
- Java高级特性部分(继承与多线程)
- java内存机制
- MFC使用HttpGet和HttpPost方法与服务器通信
- ksoap2的简单封装
- 《Android深入透析》之常用设计模式经验谈