winston 发表于 2012-2-11 19:43:02

图像处理基本算法 链码 边界跟踪

链码在图像提取的后期即模式识别是一个很重要的特征,比如进行数字识别或者文字识别都会用到链码的特征,而链码的提取则可以借助于边界跟踪算法获取边界序列,注意是边界序列而不是边界,边界很容易获取,但是要想把边界的点按照一定的顺序输出则要费些功夫。下面采用边界跟踪算法获取边界,并存储在堆栈中,(这里的堆栈实际是C++容器类,是虚拟堆栈)。


利用点的八邻域信息,选择下一个点作为边界点,这个算法需要选择一个开始点,可以选择图像上是目标点,在最上,最左的点。然后查看它的八邻域的点,从右下方45°的位置开始寻找,如果是目标点,将沿顺时针90°作为下一次寻找的方向,如果不是,则逆时针45°继续寻找,一旦找到重复上面的过程。


具体的步骤在算法中有讲解。

/************************************************************************//* 查找物体的边界,输出已排序的边界序列 适应于单一区域      *//************************************************************************///若能够输出边界点的序列则是比较有用的 #include<cv.h>
#include <highgui.h>
#include <iostream>
#include <stack>
using namespace std;



int main(){
        IplImage * image,*image2;
        image = cvLoadImage("E:\\image\\mapleleaf.tif",0);
        cvNamedWindow("image",1);
        cvShowImage("image",image);

        image2 = cvCreateImage(cvSize(image->width, image->height),image->depth,1);
        cvZero(image2);//image2 赋值为0
        //寻找区域的左上角点
        CvPoint startPoint = cvPoint(0,0);
        bool bFindStartpoint = false;
        int i ,j;
        unsigned char * ptr,*dst;
        stack<int> board;//奇数位存储x坐标,偶数位存储y坐标

        //当前扫描点
        CvPoint currentPoint = cvPoint(0,0);
        //邻域的8个点的方向
        int directions = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
        int beginDirection = 0;
        bool bFindBoardpoint = false;//寻找到邻域的边界点的判定
        for (i = 0 ; i< image->height && bFindStartpoint == false; i++)
        {
                for (j = 0 ; j< image->width && bFindStartpoint == false; j++)
                {
                        ptr = (unsigned char *)(image->imageData + i*image->widthStep + j);
                        if (*ptr == 255)
                        {
                                startPoint.x = j;
                                startPoint.y = i;
                                bFindStartpoint = true;
                                //cout<<"x:" << j <<"y :" <<i <<endl;
                        }
                }
        }

        //进行边界跟踪 每次搜索8个方向的点 找到了即停止
        currentPoint = startPoint;
    bFindStartpoint = false;
        beginDirection = 0;
        board.push(startPoint.x);
        board.push(startPoint.y);
        while (!bFindStartpoint)
        {
                bFindBoardpoint = false;
                //在8个方向寻找符合条件的边界点
                while (!bFindBoardpoint)
                {   
                        //进行出界判定不对啊 这张图不可能出界啊
                        ptr = (unsigned char *)(image->imageData + (currentPoint.y + directions)* image->widthStep + currentPoint.x + directions);
                        if (*ptr == 255)
                        {
                                bFindBoardpoint = true;
                                currentPoint.x +=directions;
                                currentPoint.y+= directions;
                                /************************************************************************/
                                /*此处添加序列存储的代码                  */
                                /************************************************************************/
                                //一、将边界存储到图片中
                                dst= (unsigned char *)image2->imageData + currentPoint.y * image2->widthStep + currentPoint.x;
                                *dst = 255;

                                //二、将边界点的序列存储到一个堆栈中
                                board.push(currentPoint.x);
                                board.push(currentPoint.y);

                                if (currentPoint.x == startPoint.x&& currentPoint.y == startPoint.y )
                                {
                                        bFindStartpoint = true;
                                }
                                //改变下次首先开始扫描的方向
                                beginDirection -= 2;
                                if (beginDirection < 0)
                                {
                                        beginDirection += 8;
                                }
                               
                               
                               
                        }
                        else
                        {
                                beginDirection ++;
                                beginDirection = beginDirection%8;
                        }
                }
                //cout<<"currentPoint    "<<currentPoint.x <<"   "<< currentPoint.y<<endl;
        }
        cvNamedWindow("image2",1);
        cvShowImage("image2",image2);
       

        //显示堆栈中的数据 顺时针存储,逆时针显示
        //注意:显示时候堆栈中已经没有数据了
/*        int x,y;
        while(!board.empty())
        {
                y = board.top();
                board.pop();
                x = board.top();
                board.pop();
                cout<<"x   "<<x<<"    y    "<<y<<endl;
        }
*/
        cvWaitKey(0);
        return 0;
}
http://hi.csdn.net/attachment/201202/11/0_1328947268vbFT.gif
http://hi.csdn.net/attachment/201202/11/0_1328947275Tat9.gif

/************************************************************************//* 轮廓跟踪算法获取物体的轮廓序列 生成边界链码   *//************************************************************************/#include<cv.h>#include <highgui.h>
#include <iostream>
#include <stack>
using namespace std;



int main(){
        IplImage * image,*image2,*image3;
        image = cvLoadImage("E:\\image\\bottle2.tif",0);
        cvNamedWindow("image",1);
        cvShowImage("image",image);

        image2 = cvCreateImage(cvSize(image->width, image->height),image->depth,1);
        image3 = cvCreateImage(cvSize(image->width, image->height),image->depth,1);
        cvZero(image2);//image2 赋值为0
        cvZero(image3);
        //寻找区域的左上角点
        CvPoint startPoint = cvPoint(0,0);
        bool bFindStartpoint = false;
        int i ,j;
        unsigned char * ptr,*dst;
        stack<int> board;//奇数位存储x坐标,偶数位存储y坐标

        //当前扫描点
        CvPoint currentPoint = cvPoint(0,0);
        //邻域的8个点的方向
        int directions = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
        int beginDirection = 0;
        bool bFindBoardpoint = false;//寻找到邻域的边界点的判定
        for (i = 0 ; i< image->height && bFindStartpoint == false; i++)
        {
                for (j = 0 ; j< image->width && bFindStartpoint == false; j++)
                {
                        ptr = (unsigned char *)(image->imageData + i*image->widthStep + j);
                        if (*ptr == 255)
                        {
                                startPoint.x = j;
                                startPoint.y = i;
                                bFindStartpoint = true;
                                //cout<<"x:" << j <<"y :" <<i <<endl;
                        }
                }
        }

        //进行边界跟踪 每次搜索8个方向的点 找到了即停止
        currentPoint = startPoint;
    bFindStartpoint = false;
        beginDirection = 0;
        board.push(startPoint.x);
        board.push(startPoint.y);
        while (!bFindStartpoint)
        {
                bFindBoardpoint = false;
                //在8个方向寻找符合条件的边界点
                while (!bFindBoardpoint)
                {   
                        //进行出界判定不对啊 这张图不可能出界啊
                        ptr = (unsigned char *)(image->imageData + (currentPoint.y + directions)* image->widthStep + currentPoint.x + directions);
                        if (*ptr == 255)
                        {
                                bFindBoardpoint = true;
                                currentPoint.x +=directions;
                                currentPoint.y+= directions;
                                /************************************************************************/
                                /*此处添加序列存储的代码                  */
                                /************************************************************************/
                                //一、将边界存储到图片中
                                dst= (unsigned char *)image2->imageData + currentPoint.y * image2->widthStep + currentPoint.x;
                                *dst = 255;

                                //二、将边界点的序列存储到一个堆栈中
                                board.push(currentPoint.x);
                                board.push(currentPoint.y);

                                if (currentPoint.x == startPoint.x&& currentPoint.y == startPoint.y )
                                {
                                        bFindStartpoint = true;
                                }
                                //改变下次首先开始扫描的方向
                                beginDirection -= 2;
                                if (beginDirection < 0)
                                {
                                        beginDirection += 8;
                                }
                               
                               
                               
                        }
                        else
                        {
                                beginDirection ++;
                                beginDirection = beginDirection%8;
                        }
                }
                //cout<<"currentPoint    "<<currentPoint.x <<"   "<< currentPoint.y<<endl;
        }
        cvNamedWindow("image2",1);
        cvShowImage("image2",image2);
       

        //显示堆栈中的数据 顺时针存储,逆时针显示
        //注意:显示时候堆栈中已经没有数据了
/*        int x,y;
        while(!board.empty())
        {
                y = board.top();
                board.pop();
                x = board.top();
                board.pop();
                cout<<"x   "<<x<<"    y    "<<y<<endl;
        }
*/

        //Board中存储着边界的序列 转化为8邻域链码,每隔10个点取样 显示

        int lianmaLength = (board.size()+5)/10;
    int* lianma = new int;

        for (i = 0 ; i< lianmaLength&& !board.empty();i += 2)
        {
                lianma = board.top();
                board.pop();
                lianma = board.top();
                board.pop();

                for (j = 0; j< 18 && !board.empty();j++)
                {
                        board.pop();
                }
        }
        //将数据在image3中显示
        int t;
        for ( t = 0; t < lianmaLength;t += 2)
        {
               i = lianma;
               j = lianma;
               ptr = (unsigned char *)image3->imageData + i*image->widthStep + j;
               *ptr = 255;
               
        }
    cvNamedWindow("image3",1);
        cvSaveImage("E:\\image\\bottle2lianma.bmp",image3);
        cvShowImage("image3",image3);


        cvWaitKey(0);
        return 0;
}




作者:renshengrumenglibing 发表于2012-2-11 15:58:54 原文链接

页: [1]
查看完整版本: 图像处理基本算法 链码 边界跟踪