|
链码在图像提取的后期即模式识别是一个很重要的特征,比如进行数字识别或者文字识别都会用到链码的特征,而链码的提取则可以借助于边界跟踪算法获取边界序列,注意是边界序列而不是边界,边界很容易获取,但是要想把边界的点按照一定的顺序输出则要费些功夫。下面采用边界跟踪算法获取边界,并存储在堆栈中,(这里的堆栈实际是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;
- }
复制代码
作者:renshengrumenglibing 发表于2012-2-11 15:58:54 原文链接
|
|