利用梯度方向在图像上提取直线的方法

本文详细介绍了从图像中提取直线的一种方法,利用梯度方向而非大小。核心步骤包括构造线支撑区域(LSR)、平面近似、属性提取和线过滤。通过源代码分析和调试,实现了算法,并在VC6环境下编译。文章提供了资源下载链接,包括 IPP 库和OpenGL库。最终展示了算法在不同图像上的应用效果。
摘要由CSDN通过智能技术生成

原始文献:

J.Brian Burns, Allen R.Hanson,Edward M.Riseman, Extracting Straight Lines,IEEE Transactions on  Pattern Analysis and Machine Intelligence,(Volume:PAMI-8 ,  Issue: 4 ),1986

文章下载地址:http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=4767808&tag=1,如果无法下载IEEE的文章就去我的资源里下载:http://download.csdn.net/detail/ihadl/6446169

作者主页:http://www.ai.sri.com/people/burns/,这里虽然列了这篇文章,但是没有找到源代码,只有一些作者的软件(http://www.ai.sri.com/software_list/),看着都好高端的样子,以后有时间可以下下来看看效果。

在pudn上下到一个该文章的源代码(http://www.pudn.com/downloads204/sourcecode/graph/detail960709.html),不知道是原作者实现的还是后人实现的,总之最后历尽千辛万苦还是可以调试成功的,也是可用的,在此感谢代码实现者!

然后就对该算法进行了研究,对程序进行了调试,前后花费近一个月时间,因此有必要总结一下。

算法的核心步骤:

Introduction中介绍了一些提取线的通用方法和存在的一些问题,其中针对的主要问题是大多数算法利用了像素梯度的大小,而没有利用梯度的方向,因此文章主要利用梯度的方向来提取直线。主要四个步骤:
一、Group pixels into line-support regions based on similarity of gradient orientation
根据梯度的方向构造LSR.主要步骤包括:
(1)选择梯度算子计算x和y方向的梯度,然后计算梯度的方向角度.
(2)利用固定间隔的区间对梯度角度结果进行分割.由于区域增长分割方法产生的偶然错误都会对结果产生巨大影响.因此使用一种固定分区的分割方法.首先将角度360度的角度范围分割为4个区间或者8个区间,然后将具体的角度归并入分好的角度区间,最后再利用邻域搜索的算法对角度区间的结果进行聚合.
(3)利用重叠间隔的区间对梯度角度结果进行分割.由于利用固定的区间会产生问题(比如不同的两条直线由于相邻且角度相近被聚合为一条;一条直线很可能被分到两个不同的LSR当分割区间恰巧将它分开).因此扩展到重叠区间的方法,先以0度为起点,45度的间隔进行一次归并,再以22.5度为起点,45度的间隔进行第二次归并,然后利用获取最长线的原则将两次的结果合并.具体步骤是:1)先获取每个LSR的长度.2)如果某个像素包含在两个不同的LSR中,它就投票给长度长的那个LSR.3)每个LSR都会得到内部像素的投票.4)取投票数在50%以上的作为LSR.大部分的LSR要么获得非常多的票,要么非常少.
二.Approximate the intensity surface by a planar surface
获得LSR以后需要确定准确的直线的位置。第一个先验知识是直线的方向垂直于LSR中各点的梯度方向。第二就是确定沿着这个直线方向的直线的具体位置。利用两平面横切的方法获取具体位置。第一个平面是梯度大小利用最小二乘拟合得到的平面,第二个平面是图像原始灰度值的平均得到的水平平面,这两个平面相交就获得了最终的直线位置。
三.Extract attributes from the line-support region and planar fit.

提取到直线以后可以计算一些线特征,文中提供了一些线特征的计算公式。
四.Filter lines on the attributes to isolate various image eventssuch as long straight lines of any contrast.

根据线特征的一些先验知识剔除不想要的线,留下目标直线。

源代码

具体代码由三个文件组成,首先是bitmap.h和bitmap.c,看代码说明好像是发现了windows.h中的bitmap类有问题,所以就自己重写的bmp的数据结构和读写函数

//
// bitmap.h
//
// header file for MS bitmap format
//
//
#ifndef BITMAP_H
#define BITMAP_H

unsigned  char * read_bmp ( const  char * fname ,  int * width ,  int * height ,  int * step );
void write_bmp ( const  char  *iname ,  int width ,  int height ,  unsigned  char  *data );

#endif

//
// bitmap.c
//
// handle MS bitmap I/O. For portability, we don't use the data structure defined in Windows.h
// However, there is some strange thing, the side of our structure is different from what it
// should though we define it in the same way as MS did. So, there is a hack, we use the hardcoded
// constanr, 14, instead of the sizeof to calculate the size of the structure.
// You are not supposed to worry about this part. However, I will appreciate if you find out the
// reason and let me know. Thanks.
//
#include  "bitmap.h"
#include  <stdio.h >
#include  <stdlib.h >
#include  <string.h >

#define BMP_BI_RGB         0L

typedef  unsigned  short BMP_WORD ;
typedef  unsigned  int   BMP_DWORD ;
typedef  int            BMP_LONG ;

typedef  struct  {
    BMP_WORD    bfType ;
    BMP_DWORD   bfSize ;
    BMP_WORD    bfReserved1 ;
    BMP_WORD    bfReserved2 ;
    BMP_DWORD   bfOffBits ;
} BMP_BITMAPFILEHEADER ;

typedef  struct  {
    BMP_DWORD   biSize ;
    BMP_LONG    biWidth ;
    BMP_LONG    biHeight ;
    BMP_WORD    biPlanes ;
    BMP_WORD    biBitCount ;
    BMP_DWORD   biCompression ;
    BMP_DWORD   biSizeImage ;
    BMP_LONG    biXPelsPerMeter ;
    BMP_LONG    biYPelsPerMeter ;
    BMP_DWORD   biClrUsed ;
    BMP_DWORD   biClrImportant ;
} BMP_BITMAPINFOHEADER ;

BMP_BITMAPFILEHEADER bmfh ;
BMP_BITMAPINFOHEADER bmih ;

unsigned  char * read_bmp ( const  char  *fname ,  int * width ,  int * height ,  int * step )  {
    FILE * file =fopen (fname ,  "rb" );
     if  (!file )  return  NULL ;

     // I am doing fread( &bmfh, sizeof(BMP_BITMAPFILEHEADER), 1, file ) in a safe way.
    fread (  &(bmfh.bfType ),  21, file );
    fread (  &(bmfh.bfSize ),  41, file );
    fread (  &(bmfh.bfReserved1 ),  21, file );
    fread (  &(bmfh.bfReserved2 ),  21, file );
    fread (  &(bmfh.bfOffBits ),  41, file );

    BMP_DWORD pos  = bmfh.bfOffBits ;

    fread (  &bmih ,  sizeof (BMP_BITMAPINFOHEADER ),  1, file  );

     // error checking
     // "BM" actually
     if  ( bmfh.bfType !=  0x4d42 )  return  NULL ;
     if  ( bmih.biBitCount  !=  24 )  return  NULL ;
    fseek ( file , pos , SEEK_SET  );

     *width  = bmih.biWidth ;
     *height  = bmih.biHeight ;

     int padWidth  =  *width  *  3;
     int pad  =  0;
     if  ( padWidth  %  4 !=  0 )  {
        pad  =  4 -  (padWidth  %  4) ;
        padWidth  += pad ;
     }
     *step  = padWidth ;
     int bytes  =  *height  * padWidth ;

     unsigned  char * data  = malloc (bytes );

     int foo  = fread ( data , bytes ,  1, file  );

     if  (!foo )  {
        free (data );
         return  NULL ;
     }

    fclose ( file  );
    
     // shuffle bitmap data such that it is (R,G,B) tuples in row-major order
     int i , j ;
    j  =  0;
     unsigned  char temp ;
     unsigned  char * in ;
     unsigned  char * out ;

    in  = data ;
    out  = data ;

     for  ( j  =  0; j  <  *height ;  ++)  {
         for  ( i  =  0; i  <  *width ;  ++)  {
            out [ 1= in [ 1] ;
            temp  = in [ 2] ;
            out [ 2= in [ 0] ;
            out [ 0= temp ;

            in  +=  3;
            out  +=  3;
         }
        in  += pad ;
     }

     return data ;
}

void write_bmp ( const  char  *iname ,  int width ,  int height ,  unsigned  char  *data )  {
     int bytes , pad ;
    bytes  = width  *  3;
    pad  =  (bytes % 4) ?  4- (bytes % 4:  0;
    bytes  += pad ;
    bytes  *= height ;

    bmfh.bfType  =  0x4d42;     // "BM"
    bmfh.bfSize  =  sizeof (BMP_BITMAPFILEHEADER )  +  sizeof (BMP_BITMAPINFOHEADER )  + bytes ;
    bmfh.bfReserved1  =  0;
    bmfh.bfReserved2  =  0;
    bmfh.bfOffBits  =  /*hack sizeof(BMP_BITMAPFILEHEADER)=14, sizeof doesn't work?*/
                      14 +  sizeof (BMP_BITMAPINFOHEADER );

    bmih.biSize  =  sizeof (BMP_BITMAPINFOHEADER );
    bmih.biWidth  = width ;
    bmih.biHeight  = height ;
    bmih.biPlanes  =  1;
    bmih.biBitCount  =  24;
    bmih.biCompression  = BMP_BI_RGB ;
    bmih.biSizeImage  =  0;
    bmih.biXPelsPerMeter  =  ( int )( 100 /  2. 54 *  72) ;
    bmih.biYPelsPerMeter  =  ( int )( 100 /  2. 54 *  72) ;
    bmih.biClrUsed  =  0;
    bmih.biClrImportant  =  0;

    FILE  *foo =fopen (iname ,  "wb" );

     // fwrite(&bmfh, sizeof(BMP_BITMAPFILEHEADER), 1, foo);
    fwrite (  &(bmfh.bfType ),  21, foo );
    fwrite (  &(bmfh.bfSize ),  41, foo );
    fwrite (  &(bmfh.bfReserved1 ),  21, foo );
    fwrite (  &(bmfh.bfReserved2 ),  21, foo );
    fwrite (  &(bmfh.bfOffBits ),  41, foo );

    fwrite (&bmih ,  sizeof (BMP_BITMAPINFOHEADER ),  1, foo );

    bytes  / = height ;
     unsigned  char * scanline  = malloc (bytes );
     int i , j ;
     for  (=  0; j  < height ;  ++)  {
        memcpy ( scanline , data  + j * 3*width , bytes  );
         for  (=  0; i  < width ;  ++)  {
             unsigned  char temp  = scanline [i * 3] ;
            scanline [i * 3= scanline [i * 3+ 2] ;
            scanline [i * 3+ 2
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值