轮廓追踪与C#实现

来源:互联网 发布:贴吧推广软件 编辑:程序博客网 时间:2024/05/16 17:48

           轮廓追踪是图像处理中常见的方法,主要目的是追踪二值图像中目标物体的外轮廓,所得结果为单像素闭合轮廓。

流       程:

                   1. 确定种子点,即追踪的起始像素(如最左上方在轮廓上的像素点);                   

                   2. 以相应的追踪规则搜索外部轮廓点。

追踪规则:以种子点为起点,按某以确定方向(如顺时针)寻找与当前轮廓点相邻(8邻域)的轮廓点(第一个相邻),再以 此点为当前轮廓点按照前述方法搜索,直到最后搜索到 的点与种子点相同为止。

注        意:搜索过程中,下一次搜索的起始方向,是上一次搜索到当前像素方向的逆时针45度方向(如果搜索方向是顺时针)。如当前像素在上个轮廓像素的右邻域,那么当前像素可以从其右上角方向搜索,因为这时其上邻域必不是轮廓像素。这样做可以减少算法的计算量。

      追踪过程如图1所示:其中红色点表示种子点,黑色点表示轮廓点,蓝色点表示目标物体内部点,搜索方向是顺时针。

      我的代码中dircection是搜索方向,定义如下:

      int[,] direction = new int[8, 2] { { -1, 0 }, { -1, +1 }, { 0, +1 }, { +1, +1 }, { +1, 0 }, { +1, -1 }, { 0, -1 }, { -1, -1 } };

      在代码中的abrect是一个矩形对象,指的是追踪目标所在矩形,这是我原来代码中要用的东西,和这个算法没有关系。

                                 

                                                                        图1.追踪过程图示

C#实现:


unsafe protected void TraceContour(byte* imagedata, int wid, int hei)        {            int stride = (wid + 3) / 4 * 4;            int offset = stride - wid;            List<Point> ContourPoints = new List<Point>();                        bool bfindstartpoint = false;            int ss = 0;            byte* p = null;            for (int i = 0; i < hei; i++)            {                imagedata[i * stride] = 0;                imagedata[i * stride + wid - 1] = 0;            }            for (int i = 0; i < wid; i++)            {                imagedata[i] = 0;                imagedata[(hei - 1) * stride + i] = 0;            }            //寻找种子点            for (int i = 1; i < hei - 1; i++)            {                p = imagedata + i * stride;                for (int j = 1; j < wid - 1; j++)                {                    if (p[j] == 255 && (p[j + 1] + p[j - 1] + p[j - stride] + p[j + stride] + p[j + stride - 1] + p[stride + j + 1] + p[j - stride - 1] + p[j - stride + 1] != 0))                    {                        bfindstartpoint = true;                        ss = i * stride + j;                        break;                    }                }                if (bfindstartpoint)                {                    break;                }            }            //寻找种子点失败            if (!bfindstartpoint)                return ;            //搜索方向            /*             * 7 0 1             * 6 + 2             * 5 4 3             */                       int begindirect = 0;//从0开始顺时针搜索            int kk = ss;            int k = 0;            int bb = 0;            bool bfindpoint = false;            Point pt = new Point();            while (bfindstartpoint)            {                bfindpoint = false;                k = begindirect;                while (!bfindpoint)                {                    bb = kk;                    kk += (stride * direction[k, 0] + direction[k, 1]);                    int ih = kk / stride;                    int iw = kk % stride;                    //如果只有一点会死循环                    //如果超出边界                    if (ih == hei || iw == wid || kk < ss || (kk >= stride * hei))                    {                        k++;                        kk = bb;                        if (k == 8)                            k = 0;                    }                    else if (imagedata[kk] == 255)                    {                        //还原到原坐标系                        pt.X = iw + abrect.X;                        pt.Y = ih + abrect.Y;                        ContourPoints.Add(pt);                        if (kk == ss)                            bfindstartpoint = false;                        begindirect = (k + 7) % 8;//逆时针旋转45度                        bfindpoint = true;                    }                    else                    {                        kk = bb;                        k++;                        if (k == 8)                            k = 0;                    }                }            }        }