c++实现BMP图像的读取及其形态学处理

来源:互联网 发布:java linux 文件上传 编辑:程序博客网 时间:2024/06/05 04:26

一、BMP文件格式:

BITMAPFILEHEADER       位图文件头

BITMAPINFOHEADER              位图信息头

RGBQUAD                         调色板

DATA                                 图像数据

前三部分结构的定义包含在头文件 Windows.h中


(1)BITMAPFILEHEADER

功能:存储文件类型、文件大小、存放位置等信息

定义:

typedef struct tagBITMAPFILEHEADER {

        WORD    bfType;

        DWORD   bfSize;

        WORD    bfReserved1;

        WORD    bfReserved2;

        DWORD   bfOffBits;

} BITMAPFILEHEADER;

说明:

bfType=0x4D42

bfSize说明文件的大小

bfReserved1=0

bfReserved2=0

bfOffBits为文件头开始到实际图像数据之间的字节偏移量

 

(2)BITMAPINFOHEADER

功能:存储图像的基本信息,图像的高度、宽度、位面数、比特数、分辨率、索引数等

定义:

typedef struct tagBITMAPINFOHEADER{

        DWORD      biSize;

        LONG       biWidth;

        LONG       biHeight;

        WORD       biPlanes;

        WORD       biBitCount;

        DWORD      biCompression;

        DWORD      biSizeImage;

        LONG       biXPelsPerMeter;

        LONG       biYPelsPerMeter;

        DWORD      biClrUsed;

        DWORD      biClrImportant;

} BITMAPINFOHEADER;

说明:

biBitCount表示每个像素所占的字节数

(3)RGBQUAD

功能:指定R、G、B不同颜色分量的强度

定义:

 

typedef struct tagRGBQUAD {

        BYTE    rgbBlue;

        BYTE    rgbGreen;

        BYTE    rgbRed;

        BYTE    rgbReserved;

} RGBQUAD;

说明:

rgbReserved=0

 

(4)DATA

图像中的数据少于或等于256时,数据是颜色在调色板中的索引。

图像为真彩色24位或者更多时,没有调色板,图像数据直接是每个像素的颜色值B、G、R。

因此,当biBitCount<=8时,colorTablesize=2的biBitCount次方*4(字节)

     当biBitCount==24时,colorTablesize=0


二、BMP操作

1、读取图像的宽度、高度、字节数

(1)分析

所要读取的信息都在BITMAPINFOHEADER部分,因此可以跳过BITMAPFILEHEDER部分,读取BITMAPINFOHEADER部分内容然后输出即可。

(2)流程图



(3)C++实现代码

#include "Windows.h"#include <iostream>using namespace std;int main(){    FILE *fp=fopen("imagetech.bmp","rb");if(fp==0)  return 0;    fseek(fp, sizeof(BITMAPFILEHEADER),0);    BITMAPINFOHEADER head;     fread(&head, sizeof(BITMAPINFOHEADER), 1,fp);        int bmpWidth = head.biWidth;    int bmpHeight = head.biHeight;    int biBitCount = head.biBitCount;         cout<<"bmpWidth:"<<bmpWidth<<"  bmpHeight:" <<bmpHeight<<"  biBitCount:"<<biBitCount<<endl;  fclose(fp);      return 1;}

(4)实验结果


2、对bmp图像进行腐蚀操作

#include <stdio.h>#include "Windows.h"#define GET(a,b) *(pBmpbuf+bmpWidth*a+b)         //获得第(i,j)坐标的像素值#define SET(a,b,t) *(pNewBmpbuf+bmpWidth*a+b)=t  //第(i,j)坐标的像素值赋为t#define lineByte ((bmpWidth*biBitCount+31)/32*4)  //每行的字节数 unsigned char* pBmpbuf=NULL;unsigned char* pNewBmpbuf=NULL;int bmpWidth;int bmpHeight;int biBitCount;unsigned long bfOffBits;bool readBMPInfo(char * bmpName){    FILE *fp=fopen(bmpName,"rb");    if (fp==0)  return false;    //判断是否为bmp图像BITMAPFILEHEADER fileHead;    fread(&fileHead, sizeof(BITMAPFILEHEADER), 1,fp);        if(fileHead.bfType != 0x4D42) //非bmp类型返回    {    fclose(fp);    printf("输入文件不是bmp类型");    return false;    }    bfOffBits=fileHead.bfOffBits;   //读取偏移位置     //将文件指针跳过位图文件头    fseek(fp, sizeof(BITMAPFILEHEADER),0);        BITMAPINFOHEADER head;    fread(&head, sizeof(BITMAPINFOHEADER), 1,fp);    bmpWidth = head.biWidth;    bmpHeight = head.biHeight;    biBitCount = head.biBitCount;    fseek(fp,bfOffBits,0);    //fp指针定位至图像起始位置 pBmpbuf=new unsigned char[bmpHeight*lineByte]; fread(pBmpbuf,1,bmpHeight*lineByte,fp);    fclose(fp);    return true;}bool grayscaleErosion(){int nWindow=3;    //操作结构元素的尺寸    int nAlign=nWindow/2;    unsigned char temp_max;    if(!pNewBmpbuf){pNewBmpbuf=new unsigned char[bmpHeight*lineByte];memcpy(pNewBmpbuf,pBmpbuf,bmpHeight*lineByte);  }         //起始位置为(1,1)点,忽略外层边缘 ,仅限3*3尺寸是这样,     for (int i=nAlign;i<bmpHeight-nAlign;i++)        for (int j=nAlign;j<bmpWidth-nAlign;j++)        {        temp_max=GET(i,j);            for (int m=i-nAlign;m<=i+nAlign;m++)            {                for (int n=j-nAlign;n<=j+nAlign;n++)                {                 if(GET(m,n)>temp_max)                 temp_max=GET(m,n);                }            }            SET(i,j,temp_max);        }        return true;}bool saveBmp(char * bmpName, char *dstName ){FILE *fp1=fopen(bmpName,"rb");FILE *fp2=fopen(dstName,"wb");  if(fp1==0||fp2==0){fclose(fp1);fclose(fp2);return 0;}unsigned char basicInfo[bfOffBits];fread(basicInfo,1,bfOffBits,fp1);fwrite(basicInfo,1,bfOffBits,fp2);fseek(fp1,bfOffBits-1,0);    //fp指针定位至图像起始位置 fwrite(pNewBmpbuf,1,bmpHeight*lineByte,fp2);    fclose(fp1);    fclose(fp2);    return 1;}int main(){char srcName[51]="imagetech.bmp";readBMPInfo(srcName);//腐蚀 grayscaleErosion();saveBmp(srcName,"Erosion.bmp");delete[] pNewBmpbuf;pNewBmpbuf=NULL;printf("  操作成功!\n\n  已在当前文件夹下生成Erosion.bmp图像\n\n");printf("请在当前文件夹下查看处理结果\n\n"); getchar();delete[] pBmpbuf;fflush(stdin);     return 1;}

二、问题

1、位图数据宽度为什么必须是4的倍数字节

Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充。

0 0