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

链码在图像提取的后期即模式识别是一个很重要的特征,比如进行数字识别或者文字识别都会用到链码的特征,而链码的提取则可以借助于边界跟踪算法获取边界序列,注意是边界序列而不是边界,边界很容易获取,但是要想把边界的点按照一定的顺序输出则要费些功夫。下面采用边界跟踪算法获取边界,并存储在堆栈中,(这里的堆栈实际是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[8][2] = {{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[beginDirection][1])* image->widthStep + currentPoint.x + directions[beginDirection][0]);
			if (*ptr == 255)
			{
				bFindBoardpoint = true;
				currentPoint.x +=  directions[beginDirection][0];
				currentPoint.y  += directions[beginDirection][1];
				/************************************************************************/
				/*  此处添加序列存储的代码                    */
				/************************************************************************/
				//一、将边界存储到图片中
				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;
}





/************************************************************************/  
/* 轮廓跟踪算法获取物体的轮廓序列 生成边界链码   */  
/************************************************************************/  
#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[8][2] = {{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[beginDirection][1])* image->widthStep + currentPoint.x + directions[beginDirection][0]);  
            if (*ptr == 255)  
            {  
                bFindBoardpoint = true;  
                currentPoint.x +=  directions[beginDirection][0];  
                currentPoint.y  += directions[beginDirection][1];  
                /************************************************************************/  
                /*  此处添加序列存储的代码                    */  
                /************************************************************************/  
                //一、将边界存储到图片中  
                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[lianmaLength];  
  
    for (i = 0 ; i< lianmaLength  && !board.empty();i += 2)  
    {  
        lianma[i+1] = board.top();  
        board.pop();  
        lianma[i] = 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[t+1];  
         j = lianma[t];  
         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;  
}  

转自http://blog.csdn.net/renshengrumenglibing/article/details/7251072

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值