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

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

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

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

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

头文件TestBmp.h如下:

 typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG; //位图文件头定义;
//其中不包含文件类型信息(由于结构体的内存结构决定,
//要是加了的话将不能正确读取文件信息)
typedef struct tagBITMAPFILEHEADER{
//WORD bfType;//文件类型,必须是0x424D,即字符“BM”
DWORD bfSize;//文件大小
WORD bfReserved1;//保留字
WORD bfReserved2;//保留字
DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER{
DWORD biSize;//信息头大小
LONG biWidth;//图像宽度
LONG biHeight;//图像高度
WORD biPlanes;//位平面数,必须为1
WORD biBitCount;//每像素位数
DWORD biCompression; //压缩类型
DWORD biSizeImage; //压缩图像大小字节数
LONG biXPelsPerMeter; //水平分辨率
LONG biYPelsPerMeter; //垂直分辨率
DWORD biClrUsed; //位图实际用到的色彩数
DWORD biClrImportant; //本位图中重要的色彩数
}BITMAPINFOHEADER; //位图信息头定义 typedef struct tagRGBQUAD{
BYTE rgbBlue; //该颜色的蓝色分量
BYTE rgbGreen; //该颜色的绿色分量
BYTE rgbRed; //该颜色的红色分量
BYTE rgbReserved; //保留值
}RGBQUAD;//调色板定义

源文件TestBmp.cpp如下:

 #include<math.h>
#include <iomanip.h>
#include <stdlib.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <fstream.h> /************************************************************************/ /*以下该模块是完成BMP图像(彩色图像是24bit RGB各8bit)的像素获取, 并存在文件名为xiang_su_zhi.txt中
*/
/************************************************************************/ //用到的全局变量 unsigned char *pBmpBuf;//读入图像数据的指针 int bmpWidth;//图像的宽 int bmpHeight;//图像的高 RGBQUAD *pColorTable;//颜色表指针 int biBitCount;//图像类型,每像素位数 /*static s[8][9]={
{-1,-2,-1,0,0,0,1,2,1},
{0,-1,-2,1,0,-1,2,1,0},
{1,0,-1,2,0,-2,1,0,-1},
{2,1,0,1,0,-1,0,-1,-2},
{1,2,1,0,0,0,-1,-2,-1},
{0,1,2,-1,0,1,-2,-1,0},
{-1,0,1,-2,0,2,-1,0,1},
{-2,-1,0,-1,0,1,0,1,2}
};*/ static s[]={-,,,-,,,-,,}; /************************************************************************/ /* 读图像的位图数据、宽、高、颜色表及 每像素位数等数据进内存,存放在相应的全局变量中
*/
/************************************************************************/ bool readBmp(char *bmpName)
{ FILE *fp=fopen(bmpName,"rb");//二进制只读方式打开指定的图像文件 if(fp==) //判断文件是否正确打开
return ; //跳过位图文件头结构BITMAPFILEHEADER,使得文件指针指向信息头的开始
fseek(fp, sizeof(BITMAPFILEHEADER),); //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中,为了获取图像的宽,高,每像素所占位数
BITMAPINFOHEADER head;
fread(&head, sizeof(BITMAPINFOHEADER), ,fp); //获取图像宽、高、每像素所占位数等信息
bmpWidth = head.biWidth;
bmpHeight = head.biHeight;
biBitCount = head.biBitCount; //定义变量,计算图像每行像素所占的字节数(必须是4的倍数)
int lineByte=(bmpWidth * biBitCount/+)/*; //灰度图像有颜色表(调色板),且颜色表表项为256
if(biBitCount==)
{
//申请颜色表所需要的空间,读颜色表进内存
pColorTable=new RGBQUAD[]; //申请256种颜色表大小的内存
fread(pColorTable,sizeof(RGBQUAD),,fp); //读取概灰度图的颜色表到pColorTable所指向的内存中
} //申请位图数据所需要的空间,读位图数据进pBmpBuf指向的内存
pBmpBuf=new unsigned char[lineByte * bmpHeight];
fread(pBmpBuf,,lineByte * bmpHeight,fp); fclose(fp);//关闭文件
return ;//读取文件成功 } /************************************************************************/ /* 给定一个图像位图数据、宽、高、颜色表指针及 每像素所占的位数等信息,将其写到指定文件中
*/
/************************************************************************/ bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)
{
//如果位图数据指针为0,则没有数据传入,函数返回
if(!imgBuf)
return ; //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
int colorTablesize=; if(biBitCount==)
colorTablesize=;//一个RGBQUAD(颜色)结构占四个字节,对于8位的灰度图而言,一共有256*4=1024个字节大小的颜色表 //待存储图像数据每行字节数为4的倍数
int lineByte=(width * biBitCount/+)/*; //以二进制写的方式打开文件
FILE *fp=fopen(bmpName,"wb");
if(fp==)
return ; //申请位图文件头结构变量,填写文件头信息
BITMAPFILEHEADER fileHead;
fileHead.bfType = 0x4D42;//bmp类型 //bfSize是图像文件4个组成部分之和
fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height;
fileHead.bfReserved1 = ;
fileHead.bfReserved2 = ; //bfOffBits是图像文件前3个部分所需空间之和
fileHead.bfOffBits=+colorTablesize; //写文件头进文件
fwrite(&fileHead, sizeof(BITMAPFILEHEADER),, fp); //申请位图信息头结构变量,填写信息头信息
BITMAPINFOHEADER head;
head.biBitCount=biBitCount;
head.biClrImportant=;
head.biClrUsed=;
head.biCompression=;
head.biHeight=height;
head.biPlanes=;
head.biSize=;
head.biSizeImage=lineByte*height;
head.biWidth=width;
head.biXPelsPerMeter=;
head.biYPelsPerMeter=; //写位图信息头进内存
fwrite(&head, sizeof(BITMAPINFOHEADER),, fp); //如果灰度图像,有颜色表,写入文件
if(biBitCount==)
fwrite(pColorTable, sizeof(RGBQUAD),, fp); //写位图数据进文件
fwrite(imgBuf, height*lineByte, , fp); //关闭文件
fclose(fp);
return ;
} void sobel()
{
//读入指定BMP文件进内存
char readPath[]="line.bmp"; //读取图像信息
readBmp(readPath); //输出图像的信息 宽度(单位像素) 高度(单位像素) 每个像素的位数
cout<<"width="<<bmpWidth<<" height="<<bmpHeight<<" biBitCount="<<biBitCount<<endl; //每行字节数(图像数据真正的宽度)
int RealWidth=(bmpWidth*biBitCount/+)/*; BYTE *pBmpSobel=new BYTE[RealWidth*bmpHeight];
memset(pBmpSobel,,RealWidth*bmpHeight); //////////////////////////////////////////////////////////////////////////
//八个方向的Sobel边缘检测
////////////////////////////////////////////////////////////////////////// /* int d,max; for(int y=1;y<bmpHeight-1;y++)
{
for(int x=1;x<RealWidth-1;x++)
{
max=0;
//////////////////////////////////////////////////////////////////////////
//分别从八个方向进行Sobel边缘化,上 下 左 右,左上,左下,右上,右下
//////////////////////////////////////////////////////////////////////////
for(int i=0;i<8;i++)
{
d=0;
//////////////////////////////////////////////////////////////////////////
//一个sobel算子和一个3*3的像素矩阵相乘得到一个边缘图像像素值
//////////////////////////////////////////////////////////////////////////
for(int y2=0;y2<3;y2++)
for(int x2=0;x2<3;x2++)
{
d+=s[i][x2+y2*3]*pBmpBuf[(y-1+y2)*RealWidth+x-1+x2];
}
////////////////////////////////////////////////////////////////////////// if(d>max)max=d; //取出八个方向上的最大值保存在max中,作为灰度图某像素点的边缘像素值
}
if(max>255)max=255; //将边缘像素值大于255的像素点 像素值置为255(白色)
pBmpSobel[y*RealWidth+x]=(BYTE)max;
}
}*/ //////////////////////////////////////////////////////////////////////////
//一个方向的Sobel边缘检测(垂直方向)
////////////////////////////////////////////////////////////////////////// int d; for(int y=;y<bmpHeight-;y++)
{
for(int x=;x<RealWidth-;x++)
{
d=;
//////////////////////////////////////////////////////////////////////////
//一个sobel算子和一个3*3的像素矩阵相乘得到一个边缘图像像素值
//////////////////////////////////////////////////////////////////////////
for(int y2=;y2<;y2++)
for(int x2=;x2<;x2++)
{
d+=s[x2+y2*]*pBmpBuf[(y-+y2)*RealWidth+x-+x2];
}
////////////////////////////////////////////////////////////////////////// if(d>)d=; //将边缘像素值大于255的像素点 像素值置为255(白色)
if(d<)d=; //将边缘像素值大于255的像素点 像素值置为255(黑色)
pBmpSobel[y*RealWidth+x]=(BYTE)d;
}
} //将图像数据存盘 char writePath[]="f.bmp"; //图片处理后再存储
saveBmp(writePath, pBmpSobel, bmpWidth, bmpHeight, biBitCount, pColorTable); //清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间
delete []pBmpBuf;
delete []pBmpSobel; if(biBitCount==)
delete []pColorTable;
} /************************************************************************/ /* 主函数 */ /************************************************************************/ void main()
{
sobel();
}

灰度原图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. Merge Sorted Array 解答

    Question Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array ...

  2. POJ3278 Catch That Cow(BFS)

    Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...

  3. python标准库 sysconfig模块

    # -*- coding: utf-8 -*-# python:2.x__author__ = 'Administrator'import sysconfig#sysconfig:解释器编译时配置#作 ...

  4. Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6786239 Android 系统的运行时库层代 ...

  5. 自适应SimpsonSimpson积分

  6. Content-Disposition的使用和注意事项(转载)

    Content-Disposition的使用和注意事项 最近不少Web技术圈内的朋友在讨论协议方面的事情,有的说web开发者应该熟悉web相 关的协议,有的则说不用很了解.个人认为这要分层次来看待这个 ...

  7. No redirect found in host configuration file (C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet.config).

    Configuration Error Description: An error occurred during the processing of a configuration file req ...

  8. Linux脚本中使用特定JDK

    有时linux系统中装了很多应用,我们又不能覆盖系统中设置的版本,此时我们就需要在脚本文件中设置特定版本. export JAVA_HOME= export CLASSPATH=.:$JAVA_HOM ...

  9. wxPython缩放图片控件的一个小例子

    前几天写程序的时候,想有个自适应的图片控件,但是一直没有找到合适的解决方案.今天终于解决了这个问题,发在这里,以供参考. 程序截图: 文件下载地址: http://files.cnblogs.com/ ...

  10. 写一个Windows上的守护进程(4)日志其余

    写一个Windows上的守护进程(4)日志其余 这次把和日志相关的其他东西一并说了. 一.vaformat C++日志接口通常有两种形式:流输入形式,printf形式. 我采用printf形式,因为流 ...