zoukankan      html  css  js  c++  java
  • 数字图像处理之sobel边缘检测

    在前两部文章介绍了几种边缘检测算法,和位图的内存结构。如果对前两篇文章已经理解透彻

    了,那么本文将带你进入数字图像处理的世界。


    本文通过C代码实现基本的sobel边缘检测,包括8个方向和垂直方向:

    代码参考之前一篇--一个实例弄清楚位图的存储结构。

    同样,代码中附有详细解释,于是我不再对代码作过多讲解:


    头文件TestBmp.h如下:

     1 typedef unsigned char BYTE;
     2 typedef unsigned short WORD;
     3 typedef unsigned int DWORD;
     4 typedef long LONG;
     5 
     6 //位图文件头定义;
     7 //其中不包含文件类型信息(由于结构体的内存结构决定,
     8 //要是加了的话将不能正确读取文件信息)
     9 typedef struct  tagBITMAPFILEHEADER{
    10     //WORD bfType;//文件类型,必须是0x424D,即字符“BM”
    11     DWORD bfSize;//文件大小
    12     WORD bfReserved1;//保留字
    13     WORD bfReserved2;//保留字
    14     DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
    15 }BITMAPFILEHEADER;
    16 
    17 typedef struct tagBITMAPINFOHEADER{
    18     DWORD biSize;//信息头大小
    19     LONG biWidth;//图像宽度
    20     LONG biHeight;//图像高度
    21     WORD biPlanes;//位平面数,必须为1
    22     WORD biBitCount;//每像素位数
    23     DWORD  biCompression; //压缩类型
    24     DWORD  biSizeImage; //压缩图像大小字节数
    25     LONG  biXPelsPerMeter; //水平分辨率
    26     LONG  biYPelsPerMeter; //垂直分辨率
    27     DWORD  biClrUsed; //位图实际用到的色彩数
    28     DWORD  biClrImportant; //本位图中重要的色彩数
    29 }BITMAPINFOHEADER; //位图信息头定义
    30 
    31 typedef struct tagRGBQUAD{
    32     BYTE rgbBlue; //该颜色的蓝色分量
    33     BYTE rgbGreen; //该颜色的绿色分量
    34     BYTE rgbRed; //该颜色的红色分量
    35     BYTE rgbReserved; //保留值
    36 }RGBQUAD;//调色板定义



    源文件TestBmp.cpp如下:

      1 #include<math.h>  
      2 #include <iomanip.h>   
      3 #include <stdlib.h>  
      4 #include <windows.h>  
      5 #include <stdio.h>  
      6 #include <stdlib.h>  
      7 #include <fstream.h>        
      8 
      9 
     10 
     11 
     12 /************************************************************************/
     13 
     14 /*以下该模块是完成BMP图像(彩色图像是24bit RGB各8bit)的像素获取,
     15 
     16                 并存在文件名为xiang_su_zhi.txt中  
     17                                                                     */
     18 /************************************************************************/
     19 
     20 //用到的全局变量 
     21   
     22 unsigned char *pBmpBuf;//读入图像数据的指针 
     23        
     24 int bmpWidth;//图像的宽  
     25 
     26 int bmpHeight;//图像的高 
     27  
     28 RGBQUAD *pColorTable;//颜色表指针  
     29 
     30 int biBitCount;//图像类型,每像素位数  
     31 
     32 /*static s[8][9]={
     33     {-1,-2,-1,0,0,0,1,2,1},
     34     {0,-1,-2,1,0,-1,2,1,0},
     35     {1,0,-1,2,0,-2,1,0,-1},
     36     {2,1,0,1,0,-1,0,-1,-2},
     37     {1,2,1,0,0,0,-1,-2,-1},
     38     {0,1,2,-1,0,1,-2,-1,0},
     39     {-1,0,1,-2,0,2,-1,0,1},
     40     {-2,-1,0,-1,0,1,0,1,2}
     41  };*/
     42 
     43 static s[9]={-1,0,1,-2,0,2,-1,0,1};
     44 
     45 
     46 /************************************************************************/
     47 
     48 /*                读图像的位图数据、宽、高、颜色表及
     49 
     50             每像素位数等数据进内存,存放在相应的全局变量中      
     51                                                                 */
     52 /************************************************************************/    
     53 
     54 bool readBmp(char *bmpName)   
     55 {
     56     
     57     FILE *fp=fopen(bmpName,"rb");//二进制只读方式打开指定的图像文件  
     58     
     59     if(fp==0)            //判断文件是否正确打开
     60         return 0;  
     61 
     62 
     63     //跳过位图文件头结构BITMAPFILEHEADER,使得文件指针指向信息头的开始 
     64      fseek(fp, sizeof(BITMAPFILEHEADER),0);  
     65 
     66     //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中,为了获取图像的宽,高,每像素所占位数 
     67     BITMAPINFOHEADER head;   
     68     fread(&head, sizeof(BITMAPINFOHEADER), 1,fp); 
     69 
     70     //获取图像宽、高、每像素所占位数等信息  
     71     bmpWidth = head.biWidth;  
     72     bmpHeight = head.biHeight;
     73     biBitCount = head.biBitCount;
     74 
     75     //定义变量,计算图像每行像素所占的字节数(必须是4的倍数)    
     76     int lineByte=(bmpWidth * biBitCount/8+3)/4*4;
     77 
     78     //灰度图像有颜色表(调色板),且颜色表表项为256  
     79     if(biBitCount==8) 
     80     {  
     81         //申请颜色表所需要的空间,读颜色表进内存  
     82         pColorTable=new RGBQUAD[256];     //申请256种颜色表大小的内存
     83         fread(pColorTable,sizeof(RGBQUAD),256,fp);  //读取概灰度图的颜色表到pColorTable所指向的内存中
     84     }   
     85 
     86     //申请位图数据所需要的空间,读位图数据进pBmpBuf指向的内存  
     87     pBmpBuf=new unsigned char[lineByte * bmpHeight];  
     88     fread(pBmpBuf,1,lineByte * bmpHeight,fp); 
     89     
     90 
     91     fclose(fp);//关闭文件   
     92     return 1;//读取文件成功 
     93     
     94 }
     95 
     96 
     97 
     98 
     99 /************************************************************************/
    100 
    101 /*        给定一个图像位图数据、宽、高、颜色表指针及
    102 
    103         每像素所占的位数等信息,将其写到指定文件中
    104                                                                       */
    105 /************************************************************************/
    106 
    107 bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)  
    108 {    
    109     //如果位图数据指针为0,则没有数据传入,函数返回  
    110     if(!imgBuf)  
    111         return 0;  
    112 
    113     //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0        
    114         int colorTablesize=0;  
    115 
    116         if(biBitCount==8)  
    117                 colorTablesize=1024;//一个RGBQUAD(颜色)结构占四个字节,对于8位的灰度图而言,一共有256*4=1024个字节大小的颜色表   
    118 
    119         //待存储图像数据每行字节数为4的倍数    
    120         int lineByte=(width * biBitCount/8+3)/4*4; 
    121         
    122         //以二进制写的方式打开文件   
    123         FILE *fp=fopen(bmpName,"wb");  
    124         if(fp==0)  
    125             return 0;  
    126 
    127         //申请位图文件头结构变量,填写文件头信息  
    128         BITMAPFILEHEADER fileHead;    
    129         fileHead.bfType = 0x4D42;//bmp类型  
    130 
    131         //bfSize是图像文件4个组成部分之和   
    132         fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height;  
    133         fileHead.bfReserved1 = 0;        
    134         fileHead.bfReserved2 = 0; 
    135         
    136 
    137         //bfOffBits是图像文件前3个部分所需空间之和        
    138         fileHead.bfOffBits=54+colorTablesize;  
    139 
    140         //写文件头进文件  
    141         fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);  
    142         
    143 
    144         //申请位图信息头结构变量,填写信息头信息  
    145          BITMAPINFOHEADER head;   
    146           head.biBitCount=biBitCount;  
    147           head.biClrImportant=0;  
    148           head.biClrUsed=0;  
    149           head.biCompression=0;  
    150           head.biHeight=height;        
    151           head.biPlanes=1;  
    152           head.biSize=40;        
    153           head.biSizeImage=lineByte*height;  
    154           head.biWidth=width;  
    155           head.biXPelsPerMeter=0;        
    156           head.biYPelsPerMeter=0; 
    157           
    158         //写位图信息头进内存   
    159         fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);    
    160 
    161         //如果灰度图像,有颜色表,写入文件   
    162             if(biBitCount==8)  
    163                 fwrite(pColorTable, sizeof(RGBQUAD),256, fp);  
    164 
    165         //写位图数据进文件  
    166         fwrite(imgBuf, height*lineByte, 1, fp); 
    167            
    168         //关闭文件    
    169         fclose(fp);  
    170         return 1;        
    171 }  
    172 
    173 
    174 
    175 
    176 
    177 void sobel()
    178 {
    179     //读入指定BMP文件进内存        
    180     char readPath[]="line.bmp";  
    181     
    182     //读取图像信息
    183     readBmp(readPath); 
    184     
    185     //输出图像的信息  宽度(单位像素) 高度(单位像素) 每个像素的位数
    186      cout<<"width="<<bmpWidth<<" height="<<bmpHeight<<" biBitCount="<<biBitCount<<endl;  
    187 
    188      //每行字节数(图像数据真正的宽度)  
    189          int RealWidth=(bmpWidth*biBitCount/8+3)/4*4;
    190 
    191 
    192          BYTE *pBmpSobel=new BYTE[RealWidth*bmpHeight];
    193          memset(pBmpSobel,0,RealWidth*bmpHeight);
    194 
    195 
    196     //////////////////////////////////////////////////////////////////////////
    197          //八个方向的Sobel边缘检测
    198     //////////////////////////////////////////////////////////////////////////
    199 
    200 /*    int d,max;
    201 
    202     for(int y=1;y<bmpHeight-1;y++)
    203     {
    204         for(int x=1;x<RealWidth-1;x++)
    205         {
    206             max=0;
    207         //////////////////////////////////////////////////////////////////////////
    208             //分别从八个方向进行Sobel边缘化,上 下 左 右,左上,左下,右上,右下
    209         //////////////////////////////////////////////////////////////////////////
    210             for(int i=0;i<8;i++)
    211             {
    212                 d=0;
    213             //////////////////////////////////////////////////////////////////////////
    214                 //一个sobel算子和一个3*3的像素矩阵相乘得到一个边缘图像像素值
    215             //////////////////////////////////////////////////////////////////////////
    216                     for(int y2=0;y2<3;y2++)
    217                         for(int x2=0;x2<3;x2++)
    218                         {
    219                             d+=s[i][x2+y2*3]*pBmpBuf[(y-1+y2)*RealWidth+x-1+x2];
    220                         }
    221             //////////////////////////////////////////////////////////////////////////
    222 
    223 
    224                     if(d>max)max=d;        //取出八个方向上的最大值保存在max中,作为灰度图某像素点的边缘像素值
    225             }
    226             if(max>255)max=255;            //将边缘像素值大于255的像素点 像素值置为255(白色)
    227             pBmpSobel[y*RealWidth+x]=(BYTE)max;
    228         }
    229     }*/
    230 
    231 
    232         //////////////////////////////////////////////////////////////////////////
    233          //一个方向的Sobel边缘检测(垂直方向)
    234     //////////////////////////////////////////////////////////////////////////
    235 
    236     int d;
    237 
    238     for(int y=1;y<bmpHeight-1;y++)
    239     {
    240         for(int x=1;x<RealWidth-1;x++)
    241         {
    242                 d=0;
    243             //////////////////////////////////////////////////////////////////////////
    244                 //一个sobel算子和一个3*3的像素矩阵相乘得到一个边缘图像像素值
    245             //////////////////////////////////////////////////////////////////////////
    246                     for(int y2=0;y2<3;y2++)
    247                         for(int x2=0;x2<3;x2++)
    248                         {
    249                             d+=s[x2+y2*3]*pBmpBuf[(y-1+y2)*RealWidth+x-1+x2];
    250                         }
    251             //////////////////////////////////////////////////////////////////////////
    252 
    253             if(d>255)d=255;    //将边缘像素值大于255的像素点 像素值置为255(白色)
    254             if(d<0)d=0;        //将边缘像素值大于255的像素点 像素值置为255(黑色)
    255             pBmpSobel[y*RealWidth+x]=(BYTE)d;
    256         }
    257     }
    258 
    259 
    260     //将图像数据存盘  
    261     
    262     char writePath[]="f.bmp";
    263     
    264     //图片处理后再存储  
    265     saveBmp(writePath, pBmpSobel, bmpWidth, bmpHeight, biBitCount, pColorTable); 
    266 
    267 
    268      //清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间  
    269     delete []pBmpBuf;  
    270     delete []pBmpSobel;
    271          
    272          if(biBitCount==8)  
    273              delete []pColorTable;
    274 }
    275 
    276 
    277 
    278 /************************************************************************/
    279 
    280 /*                             主函数                                      */
    281 
    282 /************************************************************************/
    283 
    284 
    285 void main()  
    286 {  
    287     sobel();
    288 }


    灰度原图line.bmp(垂直方向上):





    垂直方向的sobel图为f.bmp:




    八个方向的灰度原图test.bmp:




    八个方向的sobel边缘结果图f.bmp:




    对该灰度原图的垂直sobel:

    作者:vpoet
    点击这里给我发消息
    出处:http://www.cnblogs.com/vpoet/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    [APM] OneAPM 云监控部署与试用体验
    Elastic Stack 安装
    xBIM 综合使用案例与 ASP.NET MVC 集成(一)
    JQuery DataTables Selected Row
    力导向图Demo
    WPF ViewModelLocator
    Syncfusion SfDataGrid 导出Excel
    HTML Table to Json
    .net core 2.0 虚拟目录下载 Android Apk 等文件
    在BootStrap的modal中使用Select2
  • 原文地址:https://www.cnblogs.com/vpoet/p/4659774.html
Copyright © 2011-2022 走看看