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

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

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

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

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

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

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

对该灰度原图的垂直sobel:

数字图像处理之sobel边缘检测的更多相关文章

  1. Win8Metro(C#)数字图像处理--2.12Sobel边缘检测

    原文:Win8Metro(C#)数字图像处理--2.12Sobel边缘检测  [函数名称] 图像Sobel边缘检测函数SobelEdgeProcess(WriteableBitmap src) [ ...

  2. Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法

    原文:Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法  [算法说明] Canny边缘检测算法可以分为4步:高斯滤波器平滑处理.梯度计算.非极大值抑制.双阈值边缘检 测和 ...

  3. Win8Metro(C#)数字图像处理--2.14Prewitt 边缘检测

    原文:Win8Metro(C#)数字图像处理--2.14Prewitt 边缘检测  [函数名称] 图像Prewitt边缘检测函数PrewittEdgeProcess(WriteableBitmap ...

  4. Win8Metro(C#)数字图像处理--2.13Roberts边缘检测

    原文:Win8Metro(C#)数字图像处理--2.13Roberts边缘检测  [函数名称] 图像Roberts边缘检测函数RobertEdgeProcess(WriteableBitmap s ...

  5. 基础图像处理之混合空间增强——(Java:拉普拉斯锐化、Sobel边缘检测、均值滤波、伽马变换)

    相信看过冈萨雷斯第三版数字图像处理的童鞋都知道,里面涉及到了很多的基础图像处理的算法,今天,就专门借用其中一个混合空间增强的案例,来将常见的几种图像处理算法集合起来,看能发生什么样的化学反应 首先,通 ...

  6. opencv6.3-imgproc图像处理模块之边缘检测

    接opencv6.2-improc图像处理模块之图像尺寸上的操作 本文大部分都是来自于转http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutori ...

  7. OpenCV图像处理篇之边缘检测算子

    OpenCV图像处理篇之边缘检测算子 转载: http://xiahouzuoxin.github.io/notes/ 3种边缘检测算子 一阶导数的梯度算子 高斯拉普拉斯算子 Canny算子 Open ...

  8. 基于FPGA的Sobel边缘检测的实现

    前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...

  9. matlab数字图像处理 入门基础

    本代码基于张铮主编的<数字图像处理与机器视觉>一书. 源图片:lena A = imread ('lena.jpg'); %读入图像lena.jpg,赋给变量A %imwrite(A,'l ...

随机推荐

  1. Copy Constructor in Java

    Reference: TutorialPoints, GeekforGeeks The copy constructor is a constructor which creates an objec ...

  2. iOS FMDB中的使用

    n使用事务 [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:@"INSERT INTO ...

  3. LitJson处理Json

    LitJSON是一个.NET平台下处理JSON格式数据的类库,小巧.快速.它的源代码使用C#编写,可以通过任何.Net平台上的语言进行调用,目前最新版本为LitJSON 0.9. 下载地址: http ...

  4. SpringMVC(三)——其他知识

    这篇博客,看一下在Controller类中,进行结果的跳转方式,对于SpringMVC框架中异常,如何统一捕捉,还有就是S(SpringMVC)SH的整合. 一,框架默认情况下是通过转发进行跳转的,如 ...

  5. [Hapi.js] Managing State with Cookies

    hapi has built-in support for parsing cookies from a request headers, and writing cookies to a respo ...

  6. textarea 的最大高度以及最小高度

    <script type="text/javascript"> $(function(){ $("#textarea3").textareaAuto ...

  7. UNION ALL

    select field1,field2,field3,field4 from table1 where ... UNION ALL select field1,field2,field3,field ...

  8. C# sql操作

    SqlConnection con = new SqlConnection(strSqlConnection);//strSqlConnection为字符串连接          DataTable ...

  9. JSP基础学习(二)

    1.JSP页面的内容组成 静态部分:标准的HTML标签.静态的页面内容,这些内容与静态的HTML页面相同 动态部分:这些由java程序来动态生成 2.<% out.println(new jav ...

  10. iOS开发 数据库FMDB

    iOS开发  数据库FMDB 1.简介 需求作用: 如果需要保存大量的结构较为复杂的数据时候, 使用数据库, 例如交规考试项目 常用的数据库: (1)Microsoft SQL Server 2000 ...