滴水算法小结

滴水算法概述

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

  • 传统滴水算法
  • 惯性滴水算法
  • 大水滴惯性滴水算法

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=6j 。那么,建立如下关系:
    T(xi+1,yi+1)=f(xi,yi,Wi)=(xi,yi1)(xi,yi+1)(xi+1,yi+1)(xi+1,yi)(xi+1,yi1)Wi=1Wi=2Wi=3Wi=4Wi=5

    式[1-2]

  • 传统滴水算法流程描述

    1. 确定水滴起始点
    2. 计算 Σ 的值
    3. 根据 Σ 的值,代入式[1-1]计算 Wi 的值
    4. Wi 的值根据式[1-2]计算 (xi+1,yi+1)
    5. 判断 (xi+1,yi+1) 到达图片下边界时算法结束,否则转到2步

      补充 : 计算水滴的起点,选择第一个满足像素分布情况为(…0*1…10)的白色像素点(*)为起始点。其中0表示黑色像素点,1表示白色像素点。
      DFA
      图[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编写,以上仅仅为实现滴水算法的一个函数

  • 传统滴水算法缺点分析及改进方向

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
如果您希望在Unity中实现水龙头滴水的效果,可以考虑使用粒子系统来模拟水滴的效果,具体做法如下: 1. 创建一个空的游戏对象,并将其命名为“水滴”。 2. 在“水滴”游戏对象中创建一个粒子系统组件。 3. 在粒子系统组件中设置粒子的形状为球体,并将半径设置为0。这将使粒子只在一个点上产生。 4. 将粒子系统的发射速率设置为一个较小的值,例如0.1。 5. 将粒子系统的发射角度设置为0,这将使粒子只朝向正上方发射。 6. 将粒子系统的粒子生命周期设置为一个较短的时间,例如0.5秒。 7. 将粒子系统的粒子大小设置为一个较小的值,例如0.05。 8. 将粒子系统的颜色设置为蓝色,以模拟水滴的颜色。 9. 在“水滴”游戏对象中创建一个Animator组件,并创建一个动画剪辑,将粒子系统的发射速率从0逐渐增加到1,然后再逐渐减少到0。在动画剪辑中设置合适的时间曲线,以实现平滑的过渡效果。 10. 将Animator组件的“Apply Root Motion”属性设置为false,以确保动画不会移动“水滴”游戏对象。 11. 在水龙头的位置上创建一个空的游戏对象,并将其命名为“水龙头”。 12. 将“水滴”游戏对象作为“水龙头”的子对象,并将其位置放在水龙头的出水口处。 13. 在“水龙头”游戏对象上创建一个脚本,并在脚本中控制动画的播放,以实现水龙头滴水的效果。 以上是一种实现水龙头滴水效果的方法,您可以根据实际需求进行调整和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值