图像处理1-windows BMP图像文件的访问

  小编想学数字图像处理,就是机器视觉类的,本人电气工程师一枚,项目上机器人配合视觉的应用比较多,初来乍到,跟着小编一块学习吧!

  实际做项目都用成熟的东西,OPEN CV等,学习时也需要知道一些底层的东西,给一幅图片,首先需要访问图片的信息,open cv中的Mat类已经封装好了对各类图片格式的访问方法,这里自己做了一个访问位图的小程序 ,使用VS2013,本来想使用C++中的文件流读取bmp格式的图片,但调试一直没成功,所以使用C语言的文件访问方式。

  下面是的程序只访问24位真彩色图的信息,其他位数的转换起来很麻烦,这里也就不再去研究了,现在用open cv中的Mat类访问很方便。

  程序中新建了一个自定义的类,能读入24位真彩色图的信息并格式化进行输出。下面是测试的图片和结果(用像素多的位图显示非常慢)

          图像处理1-windows BMP图像文件的访问_第1张图片     图像处理1-windows BMP图像文件的访问_第2张图片

程序源码:

#include
#include
#include
#include
#include
using namespace std;

typedef struct{                                //定义一个像素,存储颜色值
    UCHAR ucBlue;                            //蓝色分量
    UCHAR ucGreen;                            //绿色分量
    UCHAR ucRed;                            //红色分量
}PIXEL;                                        //自定义像素结构体

class BMP                            //定义位图类
{
public :
    int m_rows;                        //行数(图像高度)
    int m_cols;                        //列数(图像宽度)
    int m_nBitCount;                //每个颜色占的位数
    PIXEL *m_pDate;                    //数据区域指针
    RGBQUAD *m_pRGBQUAD;            //颜色表指针
public:
    //读入位图,并将信息存放到BMP类对象中
    bool imread(char* cBitmapName);
    //将BMP类对象中的信息写入位图文件
    bool imwrite(char* cBitmapName);
    //重载输出运算符,方便显示
    friend ostream &operator<<(ostream &os,const BMP &bmp);
};

bool BMP::imread(char* cBitmapName)                                    //读入位图文件
{
    FILE* fp = fopen(cBitmapName, "rb");                            //打开位图文件
    if (NULL == fp)
    {
        cout << "bitmap file open failed! pleace retry" << endl;    //文件打开失败提示
        return false;                                                //失败则返回false
    }
    LPBITMAPFILEHEADER lpBmpFileHeader = new BITMAPFILEHEADER;        //定义位图文件头指针,申请内存区域
    LPBITMAPINFOHEADER lpBmpInfoHeader = new BITMAPINFOHEADER;        //定义位图信息头指针
    fread(lpBmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);        //读出文件头
    fread(lpBmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);        //读出信息头

    m_rows = lpBmpInfoHeader->biHeight;                                //行数
    m_cols = lpBmpInfoHeader->biWidth;                                //列数
    m_nBitCount = lpBmpInfoHeader->biBitCount;                        //每种颜色所占的位数

    if (24 == m_nBitCount)                                            //如果是24位真彩色图
    {
        fseek(fp, lpBmpFileHeader->bfOffBits, 0);                    //文件指针指向图片数据的起始位置
        //windows位图存储的宽度字节大小必须是4的倍数
        int lineByte = (lpBmpInfoHeader->biWidth * lpBmpInfoHeader->biBitCount / 8 + 3) / 4 * 4;
        UCHAR* pDateTemp = new UCHAR[lineByte*lpBmpInfoHeader->biHeight];            //申请临时区域存放读出图像数据
        fread(pDateTemp, sizeof(UCHAR), lineByte*lpBmpInfoHeader->biHeight, fp);
        m_pDate = new PIXEL[lpBmpInfoHeader->biWidth*lpBmpInfoHeader->biHeight];    //申请区域存放所有像素的颜色
        for (long row = 0; row < lpBmpInfoHeader->biHeight; ++row)                    //转化,将读出的像素存入BMP类中
        {
            for (long col = 0; col < lpBmpInfoHeader->biWidth; ++col)
            {                                                                        //每3个字节存储一个像素
                m_pDate[row*lpBmpInfoHeader->biWidth + col].ucBlue = pDateTemp[row*lineByte + col * 3 + 0];
                m_pDate[row*lpBmpInfoHeader->biWidth + col].ucGreen = pDateTemp[row*lineByte + col * 3 + 1];
                m_pDate[row*lpBmpInfoHeader->biWidth + col].ucRed = pDateTemp[row*lineByte + col * 3 + 2];
            }
        }
    }

    delete lpBmpFileHeader;                                            //释放内存
    delete lpBmpInfoHeader;
    fclose(fp);                                                        //关闭文件
    return true;
}

ostream &operator<<(ostream &os, const BMP &bmp)                    //重载<<操作符
{
    if (bmp.m_rows != 0 && bmp.m_cols != 0)
    {
        os << endl;
        os << "从位图左下角开始,从左到右,从下到上列出各像素颜色(R,G,B)";
        for (long row = 0; row < bmp.m_rows; ++row)
        {
            os << endl;
            for (long col = 0; col < bmp.m_cols; ++col)
            {
                os << "(" << (int)bmp.m_pDate[row*bmp.m_cols+col].ucRed;                //必须进行强制转化
                os << "," << (int)bmp.m_pDate[row*bmp.m_cols + col].ucGreen;
                os << "," << (int)bmp.m_pDate[row*bmp.m_cols + col].ucRed << ")" << " ";
            }
        }
    }
    return os;
}

int main()                    //测试程序
{
    BMP bmp;
    bmp.imread("test.bmp");    //读入位图文件
    cout << "图像宽度:" << bmp.m_cols << endl;
    cout << "图像高度:" << bmp.m_rows << endl;
    cout << bmp << endl;    //输出位图像素信息
    
    cin.get();                //等待输入任意字符,防止退出
    return 0;
}

  这里粘贴一下BMP图像文件的结构,由下面四个部分组成:位图文件头(Bitmap File Header)、位图信息头(Bitmap Information Header)、颜色表(Color Map)和位图数据(即图像数据),实际上需要的是图片每个像素的信息,我们试着读取到图片每个像素的信息(颜色等)。

 图像处理1-windows BMP图像文件的访问_第3张图片

  windows对位图文件头、信息头、RGBQUAD结构体的定义如下(位于wingdi.h头文件下):

 typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;     //位图文件的类型,必须为0x424d,即字符串“BM”       
        DWORD   bfSize;       //文件大小 
        WORD    bfReserved1;  //备用  
        WORD    bfReserved2;  //备用
        DWORD   bfOffBits;    //从文件头到实际位图数据的偏移字节数,即上图中前三部分大小之和
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;      //本结构体的大小,为40字节
        LONG       biWidth;      //位图的宽度,以像素为单位
        LONG       biHeight;      //位图的高度,以像素为单位
        WORD       biPlanes;     //目标设备的级别,必须为1(本人也不知道)
        WORD       biBitCount;    //每个像素所占的位数,值必须为1(黑白图像),4(16色图像),8(256色图),24(真彩色图),32位色的位图
        DWORD      biCompression;  //位图压缩类型,取值为BI_RGB(未经压缩),BI_RLE8,BI_RLE4,BI_BITFILEDS(均为windows定义的常量)
        DWORD      biSizeImage;   //实际的位图数据占用的字节数
        LONG       biXPelsPerMeter;  //指定目标设备的水平分辨率,单位是像素/m
        LONG       biYPelsPerMeter;  //指定目标设备的垂直分辨率,单位是像素/m
        DWORD      biClrUsed;    //位图实际用到的颜色数,如果该值为0,则用到的颜色数为2的biBitCount次幂
        DWORD      biClrImportant; //位图显示过程中重要的颜色数,如果该值为0,则认为所有的颜色都是重要的
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;    //该颜色的蓝色分量
        BYTE    rgbGreen;   //该颜色的绿色分量
        BYTE    rgbRed;    //该颜色的红色分量
        BYTE    rgbReserved; //备用
} RGBQUAD;(占用4字节)

  有些位图需要颜色表,有些不需要(如真彩色图)。颜色表的大小和颜色数量由位图信息头中的biBitCount决定。

  对于biBitCount=1的二值图像,每像素占1位,图像中只有两种颜色(如黑白),颜色表就只有21=2个表项,整个颜色表大小为2*sizeof(RGBQUAD)=8字节;

  对于biBitCount=8的灰度图像,每像素占8位,图像中有28=256种颜色,颜色表就有256个表项,整个颜色表大小为8*sizeof(RGBQUAD)=256字节;

  对于biBitCount=24的真彩色图像,由于每个像素3个字节中分别代表了R、G、B三分量的值(每个字节表示一个颜色分量),此时不需要颜色表。

  

转载于:https://www.cnblogs.com/lxhdianqi/p/6732414.html

你可能感兴趣的:(图像处理1-windows BMP图像文件的访问)