对于给定离散轨迹 拟合其中存在的直线方程的分析

对于给定离散轨迹 拟合其中存在的直线方程的分析
问题是这样的,有一组扇形位图,求其中每一个扇形的圆心,半径,圆心角
位图类似以下:这是一副一般扫描仪输出的结果

首先是opencv 能帮我们做得,提取图像边缘 效果如图:
void  getEdge( const  IplImage *  pImg,IplImage *  pCannyImg, int  pos){

    IplImage
*  pGray  =  cvCreateImage(cvGetSize(pImg),IPL_DEPTH_8U, 1 );
    cvCvtColor(pImg,pGray,CV_BGR2GRAY);

    cvSmooth(pGray,pCannyImg,CV_BLUR,
3 , 3 , 0 , 0 );
    cvNot(pGray,pCannyImg);
    cvCanny(pGray,pCannyImg,pos,pos
* 3 , 3 );
    cvRelease(
& pGray);
}



然后就要对边缘分割来得到一个个扇形,因为这些扇形都是整齐排列的,所以不需要什么封闭轨迹检查,直接根据点的坐标的连续性就可以判定了。不妨设横竖相差大于3个像素点为不同扇形的点。
  const   int  hgap = 3 ;
    
const   int  vgap = 3 ;
    
for ( int  row = 0 ;row < edge -> height; ++ row){
        
for ( int  col = 0 ;col < edge -> width; ++ col){
            
const  uchar *  value = ( const  uchar * )edge -> imageData + row * edge -> widthStep + col;

            
if * value  ==   255 ){
                
//  printf("%d,%d = %d\n",row,col,*value);
                points.push_back(std::make_pair(col,row));
            }
        }
    }
    Points::const_iterator iter;
    Point prev
= std::make_pair( 0 , 0 );

    
for (iter = points.begin();iter != points.end(); ++ iter){
        
if (iter -> second - prev.second  >  vgap){
            Area area;
            areas.push_front(area);
        }
        areas[
0 ].push_back( * iter);
        prev
=* iter;
    }

    prev
= std::make_pair( 0 , 0 );
    
for (Areas::iterator iter =  areas.begin();iter != areas.end(); ++ iter){
        std::sort(iter
-> begin(),iter -> end());
        
for (Area::const_iterator iter2 = iter -> begin();iter2 != iter -> end(); ++ iter2){
            
if ((iter2 -> first - prev.first > hgap)  ||  (iter2 -> first - prev.first < 0 )){
                Area area;
                result.push_front(area);
            }
            result[
0 ].push_back( * iter2);
            prev
=* iter2;
        }
    }

这样我们就得到了一组扇形的边缘轨迹。因为这些轨迹是无序排列的,所以我们需要求出这个扇形的边缘链码,才能对轨迹进行分析。
又由于扫描得到的图片有明显失真,所以用一般的8领域并不能准确得到链码,我们需要更大的领域矩阵。
求N阶领域函数:
Points getNearPoints( const  Point &  point, int  gap = 1 ){
    std::set
< Point >  s_points;
    Points          points;
    
int  x(point.first),y(point.second);
    
for ( int  i = gap;i >=- gap; -- i){
        
for ( int  j = gap;j >=- gap; -- j){
             s_points.insert(std::make_pair(x
+ i,y + j));
        }
    }

    
for (std::set < Point > ::const_iterator iter  =  s_points.begin();iter != s_points.end(); ++ iter){
        
if ( * iter != point)
            points.push_back(
* iter);
    }

    
return  points;
}
这里有一点算法优化,因为可以保证:扇形2条半径中右边的一条必定斜率为0,所以求出右边半径的2个断点很简单。因为斜率为0,即此区间上的微分为0,也即差分为0。所以半径的右断点和圆心为轨迹上最长的差分为0区间的2个端点。
有了圆心点,再根据链码 向下寻找,得到左边半径的轨迹:

由于直线的二阶导数为0 左端点即为以上轨迹中二阶差分为0的最长区间的左端点
有了2条半径的端点,不难求得此扇形的圆心角。

由于圆形角代表了每一个扇形红色的分度值,所以可以将原图修复如下:


你可能感兴趣的:(对于给定离散轨迹 拟合其中存在的直线方程的分析)