图像处理细化

2019-03-31 10:20:01 qq_38619342 阅读数 2688

转自:OpenCV学习(13) 细化算法(1)

程序编码参考经典的细化或者骨架算法文章:

T. Y. Zhang and C. Y. Suen, “A fast parallel algorithm for thinning digital patterns,” Comm. ACM, vol. 27, no. 3, pp. 236-239, 1984.

它的原理也很简单:

      我们对一副二值图像进行骨架提取,就是删除不需要的轮廓点,只保留其骨架点。假设一个像素点,我们定义该点为p1,则它的八邻域点p2->p9位置如下图所示,该算法考虑p1点邻域的实际情况,以便决定是否删除p1点。假设我们处理的为二值图像,背景为黑色,值为0,要细化的前景物体像素值为1。

 

image

算法的描述如下。

首先复制源图像到目地图像,然后建立一个临时图像,接着执行下面操作:

1. 把目地图像复制给临时图像,对临时图像进行一次扫描,对于不为0的点,如果满足以下四个条件,则在目地图像中删除该点(就是设置该像素为0),这里p2,…,p9是对应位置的像素灰度值(其为1或者0)。

   a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6

    大于等于2会保证p1点不是端点或孤立点,因为删除端点和孤立点是不合理的,小于等于6保证p1点是一个边界点,而不是一个内部点。等于0时候,周围没有等于1的像素,所以p1为孤立点,等于1的时候,周围只有1个灰度等于1的像素,所以是端点(注:端点是周围有且只能有1个值为1的像素)。

image

 

   b. p2->p9的排列顺序中,01模式的数量为1,比如下面的图中,有p2p3 => 01, p6p7=>01,所以该像素01模式的数量为2。

image

     之所以要01模式数量为1,是要保证删除当前像素点后的连通性。比如下面的图中,01模式数量大于1,如果删除当前点p1,则连通性不能保证。

image

    c. P2*p4*p6 = 0

    d. p4*p6*p8 = 0

image

      在第一次子迭代中,只是移去东南的边界点,而不考虑西北的边界点,注意p4,p6出现了2次,就是说它们有一个为0,则c,d就满足。

2. 接下来,把目地图像再次复制到临时图像,接着对临时图像进行一次扫描,如果不为0的点它的八邻域满足以下4个条件,则在目地图像中删除该点(就是设置该像素为0)

    a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6

    b. p2->p9的排列顺序中,01模式的数量(这里假设二值图非零值为1)为1。

    c. p2*p4*p8 = 0

    d. p2*p6*p8 = 0

image

第二次迭代则相反,会移去西北的边界点,注意p2,p8出现了2次,就是说它们有一个为0,则c,d就满足。

 

执行完上面两个步骤后,就完成了一次细化算法,我们可以多次迭代执行上述过程,得到最终的骨架图。

 

细化算法代码如下:

void gThin::cvThin(cv::Mat& src, cv::Mat& dst, int intera)
    {
    if(src.type()!=CV_8UC1)
        {
        printf("只能处理二值或灰度图像\n");
        return;
        }
    //非原地操作时候,copy src到dst
    if(dst.data!=src.data)
        {
        src.copyTo(dst);
        }

下面是三次细化的结果,可以看出在垂直方向H变短了,感觉这是不完美的地方。

image

下面我们对两个汉字进行5次迭代细化,结果如下:

imageimage

程序代码:工程FirstOpenCV11

2019-08-29 09:13:51 weixin_41887615 阅读数 210

**细化算法 **

欢迎在下面留言

原理:以后再补,原理差不多,

代码:

/*细化算法
 */
void *Thinning(QImage &image,QImage &optImage)
{
    int height = image.height();
    int width = image.width();

    //四个条件

    bool bCondition1;
    bool bCondition2;
    bool bCondition3;
    bool bCondition4;


    //5 x 5 领域
    unsigned char neighbour[5][5];

    bool bModified = true;

    while (bModified)
    {
        bModified = false;
        for(int i = 2; i<height-2; i++)
        {
            for(int j = 2; j<width-2; j++)
            {
                bCondition1 = false;
                bCondition2 = false;
                bCondition3 = false;
                bCondition4 = false;

                BYTE data = QColor(image.pixel(j,i)).red();

                if(data == 255)
                {
                    continue;
                }


                //获得当前5 x 5领域内的黑色的点,白色用 0 代表,黑色用 1 代表
                for(int h = 0; h<5; h++)
                {
                    for(int w = 0; w<5; w++)
                    {
                        neighbour[h][w] = (QColor(image.pixel(j,i)).red() == 0);
                    }
                }

                //逐个判断条件
                //判断  2<=NZ(P1)<=6
                int nCount = neighbour[1][1] + neighbour[1][2] + neighbour[1][3] +
                             neighbour[2][1] + neighbour[2][3] +
                             neighbour[3][1] + neighbour[3][2] + neighbour[3][3];
                if(nCount >=2 && nCount<=6)
                {
                    bCondition1 = true;
                }

                //判断Z0(P1) = 1
                nCount = 0;

                if(neighbour[1][2] == 0 && neighbour[1][1] == 1)
                {
                    nCount ++;
                }

                if(neighbour[1][1] == 0 && neighbour[2][1] == 1)
                {
                    nCount ++;
                }

                if(neighbour[2][1] == 0 && neighbour[3][1] == 1)
                {
                    nCount ++;
                }

                if(neighbour[3][1] == 0 && neighbour[3][2] == 1)
                {
                    nCount ++;
                }

                if(neighbour[3][2] == 0 && neighbour[3][3] == 1)
                {
                    nCount ++;
                }

                if(neighbour[3][3] == 0 && neighbour[2][3] == 1)
                {
                    nCount ++;
                }

                if(neighbour[2][3] == 0 && neighbour[1][3] == 1)
                {
                    nCount ++;
                }

                if(neighbour[1][3] == 0 && neighbour[1][2] == 1)
                {
                    nCount ++;
                }

                if(nCount == 1)
                {
                    bCondition2 = true;
                }

                //P2 x P4 x P8 = 0 或者Z0(P2) != 1
                if(neighbour[1][2] * neighbour[2][1] * neighbour[2][3] == 0)
                {
                    bCondition3 = true;
                }
                else {
                    nCount = 0;

                    if(neighbour[0][2] == 0 && neighbour[0][1] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[0][1] == 0 && neighbour[1][1] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[1][1] == 0 && neighbour[2][1] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[2][1] == 0 && neighbour[2][2] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[2][2] == 0 && neighbour[2][3] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[2][3] == 0 && neighbour[1][3] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[1][3] == 0 && neighbour[0][3] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[0][3] == 0 && neighbour[0][2] == 1)
                    {
                        nCount ++;
                    }

                    if(nCount != 1)
                    {
                        bCondition3 = true;
                    }
                }

                //判断P2 x P4 x P6 = 0; 或者Z0(P4) != 1;
                if(neighbour[1][2] * neighbour[2][1] * neighbour[3][2] == 0)
                {
                    bCondition4 = true;
                }
                else {
                    nCount = 0;

                    if(neighbour[1][1] == 0 && neighbour[1][0] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[1][0] == 0 && neighbour[2][0] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[2][0] == 0 && neighbour[3][0] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[3][0] == 0 && neighbour[3][1] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[3][1] == 0 && neighbour[3][2] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[3][2] == 0 && neighbour[2][2] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[2][2] == 0 && neighbour[1][2] == 1)
                    {
                        nCount ++;
                    }

                    if(neighbour[1][2] == 0 && neighbour[1][1] == 1)
                    {
                        nCount ++;
                    }

                    if(nCount != 1)
                    {
                        bCondition4 = true;
                    }
                }

                //如果四个条件满足的话就进行细化
                if(bCondition1 && bCondition2 && bCondition3 && bCondition4)
                {
                    optImage.setPixel(j,i,qRgb(255,255,255));
                    bModified = true;
                }
                else {
                    optImage.setPixel(j,i,qRgb(0,0,0));
                }
            }
        }
    }


    return 0;
}
2012-11-17 09:37:21 Vast_Sea 阅读数 6375


From:  http://www.dakaren.com/index.php/archives/199.htm


二、细化

  图像处理中物体的形状信息是十分重要的,为了便于描述和抽取图像特定区域的特征,对那些表示物体的区域通常需要采用细化算法处理,得到与原来物体区域形状近似的由简单的弧或曲线组成的图形,这些细线处于物体的中轴附近,这就是所谓的图像的细化。通俗的说图像细化就是从原来的图像中去掉一些点,但仍要保持目标区域的原来形状,通过细化操作可以将一个物体细化为一条单像素宽的线,从而图形化的显示出其拓补性质。实际上,图像细化就是保持原图的骨架。所谓骨架,可以理解为图象的中轴,例如一个长方形的骨架是它的长方向上的中轴线;正方形的骨架是它的中心点;圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。对于任意形状的区域,细化实质上是腐蚀操作的变体,细化过程中要根据每个像素点的八个相邻点的情况来判断该点是否可以剔除或保留。下面我们给几个例子来说明如何判断当前像素点是否该保留或剔除。

 
图二 根据某点的八个相邻点的情况来判断该点是否能删除

  上图给出了当前需要处理的像素点在不同的八邻域条件下的情况,可以看出:(1)不能删,因为它是个内部点,我们要求的是骨架,如果连内部点也删了,骨架也会被掏空的;(2)不能删,和(1)是同样的道理;(3)可以删,这样的点不是骨架;(4)不能删,因为删掉后,原来相连的部分断开了;(5)可以删,这样的点不是骨架;(6)不能删,因为它是直线的端点,如果这样的点删了,那么最后整个直线也被删了,剩不下什么;(7)不能删,因为孤立点的骨架就是它自身。 总结一下,有如下的判据:1.内部点不能删除;2.孤立点不能删除;3.直线端点不能删除;4.如果P是边界点,去掉P后,如果连通分量不增加,则P可以删除。我们可以根据上述的判据,事先做出一张表,从0到255共有256个元素,每个元素要么是0,要么是1。我们根据某点(当然是要处理的黑色点了)的八个相邻点的情况查表,若表中的元素是1,则表示该点可删,否则保留。查表的方法是,设白点为1,黑点为0;左上方点对应一个8位数的第一位(最低位),正上方点对应第二位,右上方点对应的第三位,左邻点对应第四位,右邻点对应第五位,左下方点对应第六位,正下方点对应第七位,右下方点对应的第八位,按这样组成的8位数去查表即可。例如上面的例子中(1)对应表中的第0项,该项应该为0;(2)对应37,该项应该为0;(3)对应173,该项应该为1;(4)对应231,该项应该为0;(5)对应237,该项应该为1;(6)对应254,该项应该为0;(7)对应255,该项应该为0。仔细考虑当前像素点的各种八邻域的情况,我们可以得到一个细化操作查找表,该表在下面的细化算法中详细介绍。

  为了避免分裂物体,细化的过程分为两个步骤,第一步是正常的腐蚀操作,但是它是有条件的,也就是说那些被标记的可除去的像素点并不立即消去;在第二步中,只将那些消除后并不破坏连通性的点消除,否则的话保留这些边界点。以上的步骤是在一个3×3邻域内运算,可以通过查表实现细化的操作。算法的实现步骤如下:

  1) 定义一个3×3模板和一个查找表,模板和查找表分别如图二和表一所示:

1 2 4
128 256 8
64 32 16

图二 细化模板

erasetable[256]={
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,
0,0,0,0,0,0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,1,0,0,1,1,
1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,
0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,
1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0
};

  
表一 细化查找表

  2)对二值图像从上到下、从左到右进行扫描;该过程结束后再对图像进行从左到右,从上到下的扫描;如果图像中当前像素点的灰度值为”0″,且其左右(第一次扫描过程考虑左右像素点)或上下(第二次扫描过程考虑上下两个像素点)两个像素点中有任意一个为”255″则转至步骤三,否则回转到步骤二;

  3) 该像素点为中心的3×3区域内的各个像素值和定义的模板中的权值进行卷积求和,得到表4.1中的查找索引值k;

  4) 根据这个索引值k得到表里相应的数据,如果为”1″,那么该像素点的灰度值设为”255″,如果为”0″,则该像素点的灰度值为”0″。

  5) 图像从头至尾扫描二遍后,如果该次扫描修改了图像中的点,则跳转至步骤二,开始新的一轮扫描。否则图像细化结束。


2014-02-17 21:03:04 qianchenglenger 阅读数 33253

     在我们进行图像处理的时候,有可能需要对图像进行细化,提取出图像的骨架信息,进行更加有效的分析。

     图像细化(Image Thinning),一般指二值图像的骨架化(Image Skeletonization) 的一种操作运算。

     所谓的细化就是经过一层层的剥离,从原来的图中去掉一些点,但仍要保持原来的形状,直到得到图像的骨架。骨架,可以理解为图象的中轴。

     好的细化算法一定要满足:
  • 收敛性;
  • 保证细化后细线的连通性;
  • 保持原图的基本形状;
  • 减少笔画相交处的畸变;
  • 细化结果是原图像的中心线;
  • 细化的快速性和迭代次数少;

    这里,我们对“Zhang并行快速细化算法”进行了实现(注意,该算法为并行算法,而我们在实现过程中并没有并行化处理,所以,效率并没有达到最好)。

    参考资料

  • 细化算法
  • 论文 A fast parallel algorithm for thinning digital patterns
    #include <opencv2/opencv.hpp>
    #include <opencv2/core/core.hpp>
    #include <iostream>
    #include <vector>
    
    
    /**
     * @brief 对输入图像进行细化
     * @param src为输入图像,用cvThreshold函数处理过的8位灰度图像格式,元素中只有0与1,1代表有元素,0代表为空白
     * @param maxIterations限制迭代次数,如果不进行限制,默认为-1,代表不限制迭代次数,直到获得最终结果
     * @return 为对src细化后的输出图像,格式与src格式相同,元素中只有0与1,1代表有元素,0代表为空白
     */
    cv::Mat thinImage(const cv::Mat & src, const int maxIterations = -1)
    {
        assert(src.type() == CV_8UC1);
        cv::Mat dst;
        int width  = src.cols;
        int height = src.rows;
        src.copyTo(dst);
        int count = 0;  //记录迭代次数
        while (true)
        {
            count++;
            if (maxIterations != -1 && count > maxIterations) //限制次数并且迭代次数到达
                break;
            std::vector<uchar *> mFlag; //用于标记需要删除的点
            //对点标记
            for (int i = 0; i < height ;++i)
            {
                uchar * p = dst.ptr<uchar>(i);
                for (int j = 0; j < width; ++j)
                {
                    //如果满足四个条件,进行标记
                    //  p9 p2 p3
                    //  p8 p1 p4
                    //  p7 p6 p5
                    uchar p1 = p[j];
                    if (p1 != 1) continue;
                    uchar p4 = (j == width - 1) ? 0 : *(p + j + 1);
                    uchar p8 = (j == 0) ? 0 : *(p + j - 1);
                    uchar p2 = (i == 0) ? 0 : *(p - dst.step + j);
                    uchar p3 = (i == 0 || j == width - 1) ? 0 : *(p - dst.step + j + 1);
                    uchar p9 = (i == 0 || j == 0) ? 0 : *(p - dst.step + j - 1);
                    uchar p6 = (i == height - 1) ? 0 : *(p + dst.step + j);
                    uchar p5 = (i == height - 1 || j == width - 1) ? 0 : *(p + dst.step + j + 1);
                    uchar p7 = (i == height - 1 || j == 0) ? 0 : *(p + dst.step + j - 1);
                    if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
                    {
                        int ap = 0;
                        if (p2 == 0 && p3 == 1) ++ap;
                        if (p3 == 0 && p4 == 1) ++ap;
                        if (p4 == 0 && p5 == 1) ++ap;
                        if (p5 == 0 && p6 == 1) ++ap;
                        if (p6 == 0 && p7 == 1) ++ap;
                        if (p7 == 0 && p8 == 1) ++ap;
                        if (p8 == 0 && p9 == 1) ++ap;
                        if (p9 == 0 && p2 == 1) ++ap;
    
                        if (ap == 1 && p2 * p4 * p6 == 0 && p4 * p6 * p8 == 0)
                        {
                            //标记
                            mFlag.push_back(p+j);
                        }
                    }
                }
            }
    
            //将标记的点删除
            for (std::vector<uchar *>::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
            {
                **i = 0;
            }
    
            //直到没有点满足,算法结束
            if (mFlag.empty())
            {
                break;
            }
            else
            {
                mFlag.clear();//将mFlag清空
            }
    
            //对点标记
            for (int i = 0; i < height; ++i)
            {
                uchar * p = dst.ptr<uchar>(i);
                for (int j = 0; j < width; ++j)
                {
                    //如果满足四个条件,进行标记
                    //  p9 p2 p3
                    //  p8 p1 p4
                    //  p7 p6 p5
                    uchar p1 = p[j];
                    if (p1 != 1) continue;
                    uchar p4 = (j == width - 1) ? 0 : *(p + j + 1);
                    uchar p8 = (j == 0) ? 0 : *(p + j - 1);
                    uchar p2 = (i == 0) ? 0 : *(p - dst.step + j);
                    uchar p3 = (i == 0 || j == width - 1) ? 0 : *(p - dst.step + j + 1);
                    uchar p9 = (i == 0 || j == 0) ? 0 : *(p - dst.step + j - 1);
                    uchar p6 = (i == height - 1) ? 0 : *(p + dst.step + j);
                    uchar p5 = (i == height - 1 || j == width - 1) ? 0 : *(p + dst.step + j + 1);
                    uchar p7 = (i == height - 1 || j == 0) ? 0 : *(p + dst.step + j - 1);
    
                    if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
                    {
                        int ap = 0;
                        if (p2 == 0 && p3 == 1) ++ap;
                        if (p3 == 0 && p4 == 1) ++ap;
                        if (p4 == 0 && p5 == 1) ++ap;
                        if (p5 == 0 && p6 == 1) ++ap;
                        if (p6 == 0 && p7 == 1) ++ap;
                        if (p7 == 0 && p8 == 1) ++ap;
                        if (p8 == 0 && p9 == 1) ++ap;
                        if (p9 == 0 && p2 == 1) ++ap;
    
                        if (ap == 1 && p2 * p4 * p8 == 0 && p2 * p6 * p8 == 0)
                        {
                            //标记
                            mFlag.push_back(p+j);
                        }
                    }
                }
            }
    
            //将标记的点删除
            for (std::vector<uchar *>::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
            {
                **i = 0;
            }
    
            //直到没有点满足,算法结束
            if (mFlag.empty())
            {
                break;
            }
            else
            {
                mFlag.clear();//将mFlag清空
            }
        }
        return dst;
    }
    
    
    int main(int argc, char*argv[])
    {
        //获取图像
        if (argc != 2)
        {
            std::cout << "参数个数错误!" << std::endl;
            return -1;
        }
        cv::Mat src = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
        if (src.empty())
        {
            std::cout << "读取文件失败!" << std::endl;
            return -1;
        }
    
        //将原图像转换为二值图像
        cv::threshold(src, src, 128, 1, cv::THRESH_BINARY);
        //图像细化
        cv::Mat dst = thinImage(src);
        //显示图像
        dst = dst * 255;
        cv::namedWindow("src1", CV_WINDOW_AUTOSIZE);
        cv::namedWindow("dst1", CV_WINDOW_AUTOSIZE);
        cv::imshow("src1", src);
        cv::imshow("dst1", dst);
        cv::waitKey(0);
    }
    

    运行效果

    1原图像


    2.运行效果



  • 2017-01-15 20:49:20 klose93 阅读数 14897

      二值图像的细化是讨论将一个图像中的黑色部分沿着它的中心轴线将其细化为一个像素宽的线条的处理过程,细化的结果能基本保留图形中黑色部分的拓扑结构。图像细化是图像模式识别的关键步骤。快速细化算法的思想是优化了原细化算法中由边界逐层消除黑色像素点的过程,提高细化效率。


                                     细化前                                                                                                细化后(灰色为去除点)


    细化算法

    本算法基于逐层剥取理念,快速细化算法改进了反复扫描的过程,顺序、逆序搜索两次,确定每个点的层数,通过层数可判断该点属于边界点还是骨架, 因而优化算法的效率,大量减少程序运算时间。


    算法步骤:


    假设黑色值为1,白色为0.

    第一步,从上到下,从左到右依次扫描每一个点,若当前点(x,y)为黑点时,需判断其右上、上、左上和左四点的情况。(x-1,y+1) (x-1,y) (x-1,y-1) (x,y-1) 这四点可以理解为当前点是被该四点包围,该点层数即四点层数最小值多一层;如果当前点(x,y)为白色,层数值赋为0。



    第二步,自下而上,自右而左,与第一步相似的判断每个点的状态,若当前点是黑点,于是判断其左下、下、右下和右四点的情况(图6)。(x+1,y-1) (x+1,y) (x+1,y+1) (x,y+1)四点包围了当前点,同样取这四点层数的最小值加1 作为该点层数值;如果当前点(x,y)为白色,层数值赋为0。


    与此同时,既然已经求得每一个点上包围层数值和下包围层数值,每个点的实际层数其实就是两种层数值中最小值(图7)。

    M[x][y]=Min(F[x][y],G[x][y])



    第三步,从上到下,从左到右依次扫描每一个点,此时需要判断该点8 方向(图7)范围内所有点层数的情况。如果当前点的层数值是周围相邻点中最大,该点即保留;如果当前点的层数值并非最大,该点即可删去。

    M[x][y]==Max(M[x+i][y+i]│(-1<=i,j<=1))? 保留:删去


    综上步骤,即完成了该图像细化的全部过程,算法只需遍历3 次,就能将一幅图像进行快速细化。

      MATLAB代码
    %二值化   
    binary=imread('PIC_NAME');
    [high,weight]=size(binary);
    F=zeros(high,weight);
    G=zeros(high,weight);
    M=zeros(high,weight);
    out=zeros(high,weight);
    for i=2:high-1
        for j=2:weight-1
            if binary(i,j)==0
                F(i,j)=0;
            else
                mi=[F(i,j-1),F(i-1,j-1),F(i-1,j),F(i-1,j+1)];
                F(i,j)=min(mi)+1;
            end
        end
    end
    for i=high-1:-1:2
        for j=weight-1:-1:2
            if binary(i,j)==0
                G(i,j)=0;
            else
                mi=[G(i+1,j-1),G(i+1,j),G(i+1,j+1),G(i,j+1)];
                G(i,j)=min(mi)+1;
            end
        end
    end


    for i=2:high-1
        for j=2:weight-1
            mi=[F(i,j),G(i,j)];
            M(i,j)=min(mi);
        end
    end


    for i=2:high-1
        for j=2:weight-1
            ma=[M(i,j-1),M(i-1,j-1),M(i-1,j),M(i-1,j+1),M(i+1,j-1),M(i+1,j),M(i+1,j+1),M(i,j+1)];
            if M(i,j)==max(ma)
                out(i,j)=M(i,j);
            else
                out(i,j)=0;
            end
        end
        
    end


    imshow(out);








                
            




    matlab——图像细化

    阅读数 5255