图像处理 基于Visual C++编程 学习笔记 (2)显示bmp图像

bmp文件信息头

为了存储 bmp位图的头文件(14byte) 和位图信息(40byte),开一个DATATYPE文件来存

#ifndef __DATATYPE
#define __DATATYPE
typedef struct _BMPFileHeader
{  unsigned char B;
    unsigned char M;
    unsigned long FileSize;
    unsigned long Reserved1;
    //没有Resevered2 但书上有
    unsigned long HeaderLength;
}BMPFileHeader;
typedef struct _BMPFileInfo
{  unsigned long InfoSize;
    unsigned long ImageWidth;
    unsigned long ImageHeight;
    unsigned short  Level;
    unsigned short  ColorDepth;
    unsigned long Compress;
    unsigned long PixelBytes;
    unsigned long horizon;
    unsigned long vertical;
    unsigned long offset1;
    unsigned long offset2;
}BMPFileInfo;
typedef struct _Complex
{
    double r,i;
}Complex;
#define Pi 3.14159265358979323846
#endif

接下来读取图像

void CBMPALGORITHMDlg::OnMenuopen() 
{
    CDC *pDC = m_image1.GetDC();
    CRect myRECT;
    m_image1.GetClientRect(&myRECT);
    // TODO: Add your command handler code here
    char szFilter[]="BMP Files (*.bmp)|*.bmp|All Files(*.*)|*.*||";
    CFileDialog dlg( TRUE,"BMP",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,szFilter ); 
    if(dlg.DoModal() == IDOK) 
    { 
        CString strPathName = dlg.GetPathName();   
        imgbasic im(strPathName.GetBuffer(0));
        SetDlgItemText(IDC_OUTPUT,im.getInfo());//输出路径
        im.imshow(pDC,myRECT);
       // MessageBox("ok","hi~",MB_OK);
    } 
    m_image1.ReleaseDC(pDC);
}

CString中GetBuffer方法可以将CString转为char *

 GetBuffer(0)表示从头开始

接下来显示图像和bmp文件头及其他信息

图像信息收集:

char* imgbasic::getInfo()const
{
    char *info;
    info=(char*)malloc(sizeof(char)*500);
    info[0]='\0';
//    sprintf(info,"12132\r\n");
//    sprintf(info+7,"aaa\r\n");
    //path
    sprintf(info+strlen(info),"---------path---------\r\n");
    sprintf(info+strlen(info),"FilePath:%s\r\n",filepath);
    //BMPHeader
    sprintf(info+strlen(info),"-------BMPHeader-------\r\n");
    sprintf(info+strlen(info),"FileType:%c %c P\r\n",MyHeader.B,MyHeader.M);
    sprintf(info+strlen(info),"FileSize:%ld bytes\r\n",MyHeader.FileSize);
    sprintf(info+strlen(info),"HeaderLength:%ld \r\n",MyHeader.HeaderLength);
    //BMPFileInfo
    sprintf(info+strlen(info),"------BMPFileInfo------\r\n");
    sprintf(info+strlen(info),"InfoSize:%ld\r\n",MyInfo.InfoSize);
    sprintf(info+strlen(info),"ImageWidth:%ld\r\n",MyInfo.ImageWidth);
    sprintf(info+strlen(info),"ImageHeight:%ld\r\n",MyInfo.ImageHeight);
    sprintf(info+strlen(info),"Height*Width:%ld\r\n",MyInfo.ImageHeight*MyInfo.ImageWidth*3);
    sprintf(info+strlen(info),"Level:%ld\r\n",MyInfo.Level);
    sprintf(info+strlen(info),"ColorDepth:%ld\r\n",MyInfo.ColorDepth);
    sprintf(info+strlen(info),"PixelBytes:%ld\r\n",MyInfo.PixelBytes);
    sprintf(info+strlen(info),"Horizon:%ld\r\n",MyInfo.horizon);
    sprintf(info+strlen(info),"Vertical:%ld\r\n",MyInfo.vertical);
    sprintf(info+strlen(info),"ColorUsed:%ld\r\n",MyInfo.offset1);//不知为何显示为0
    sprintf(info+strlen(info),"ColorImportant:%ld\r\n",MyInfo.offset2);//不知为何显示为0

    return info;
}

图像信息显示到文本框

imgbasic::imgbasic(char *fn)
{
    strcpy(filepath,fn);
    FILE *mybmp;
    if(mybmp=fopen(filepath,"rb"))//以二进制形式读取
    {
    //    fread(&MyHeader,10,1,mybmp);//位图头文件是14个字节,此处用结构体读入有问题
        fread(&MyHeader.B,1,1,mybmp);
        fread(&MyHeader.M,1,1,mybmp);
        fread(&MyHeader.FileSize,1,4,mybmp);
        fread(&MyHeader.Reserved1,1,4,mybmp);
        fread(&MyHeader.HeaderLength,1,4,mybmp);

        fread(&MyInfo,40,1,mybmp);//位图信息头40个字节
        raw_img=(unsigned char*)malloc(sizeof(unsigned char)*MyInfo.PixelBytes);
        fread(raw_img,MyInfo.PixelBytes,1,mybmp);
        fclose(mybmp);

        //查看raw图像,在ps中设置宽度,高度,通道数量3,隔行,8位
        FILE *f = fopen("t.raw","wb");
        fwrite(raw_img, MyInfo.PixelBytes,1, f);
        fclose(f);
    }
    else{
        AfxMessageBox("CAN'T OPEN FILE!", MB_OK);
    }
}

图像的快速显示:

void imgbasic::imshow(CDC *pDC, CRect rc)const
{
    SetDIBitsToDevice(                                                //显示图像速度快;
        pDC->m_hDC,
        (rc.Width()-vImageWidth())/2,
        (rc.Height()-vImageHeight())/2,
        vImageWidth(),
        vImageHeight(),
        0,0,0,
        vImageHeight(),
        raw_img,
        (tagBITMAPINFO *)(&MyInfo),
        DIB_RGB_COLORS
    ); 
}

至此的成果:

 

bmp慢速显示法

快速显示法是系统集成的,为了深入学习,一定要回慢速显示法

到这里我们已经能够成功的读取bmp图像的几个重要信息:

1.路径filepath

2.宽MyInfo.ImageWidth

3.高MyInfo.ImageHeight

4.文件大小MyHeader.FileSize

5.像素大小MyInfo.PixelBytes

从上面的图片可以看到,229*341的图像实际的文件大小是234662

然而229*3*341= 234267(即341行,每行存每个像素的RGB值)

这里就要考虑bmp文件在内存中的存储方式了

在内存中,文件必须存储为4的倍数(因为每个像素的类型是unsigned char,而内存中二进制必须4个4个存)

所以对于每行,必须取4的整数倍(末尾补0)

229*3=687

687/4=171.75

取整数倍后即687/4*4=688

所以得到(229*3/4*4)*341=234608  BYTE

在加上bmp头文件和位图信息的54个字节,所以FileSize=234608+54=234662

接下来去除末尾补0的部分转存raw_img为img(快速显示时不用去除,系统集成)

void imgbasic::ReadBitData()
{
    unsigned int i,_i=0;
    unsigned int _img_w;

    _img_w=vImageWidth()*3;
    if((_img_w%4)!=0)_img_w=((vImageWidth()*3)/4+1)*4;//保证_img_w是4的倍数
    img=(unsigned char*)malloc(sizeof(unsigned char)*data_size);
    for(i=0;i<vFileSize()-54;i++){
            if(i%_img_w<vImageWidth()*3){
                img[_i]=raw_img[i];
                _i++;
            }
    }
}

然后显示图像

void imgbasic::imshow(CDC *pDC, CRect rc)//慢速显示
{
    ReadBitData();
    unsigned int i,j;
    for(i=0;i<vImageHeight();i++){
        for(j=0;j<vImageWidth();j++){
            unsigned char R = img[3*(i*vImageWidth() + j)];
            unsigned char G = img[3*(i*vImageWidth() + j) + 1];
            unsigned char B = img[3*(i*vImageWidth() + j) + 2];
            pDC->SetPixel((rc.Width()-vImageWidth())/2+j,(rc.Height()-vImageHeight())/2+i,RGB(R,G,B));
        }
    }
}

效果如下:

 发现问题:

1.图像上下颠倒了

2.颜色不对

原因:

1.bmp的像素数据从底端的一行开始向上存入文件,行内仍然保持从左至右

2.像素数据存放的顺序是BGR,而非RGB

因此接下来进行两个操作:

1.转置图像

void imgbasic::InvertImg()
{
    unsigned char temp;
    unsigned int i,j,x,y;
    x=vImageWidth()*3;
    y=vImageHeight();
    
    for(i=0;i<y/2;i++){
        for(j=0;j<x;j++){
            temp=img[i*x+j];
            img[i*x+j]=img[(y-i-1)*x+j];
            img[(y-i-1)*x+j]=temp;
        }
    }
}

2.R与B互换

void imgbasic::FlipRGB()
{
    unsigned char temp;
    unsigned int i,j,x,y;
    x=vImageWidth();
    y=vImageHeight();
    for(i=0;i<y;i++){
        for(j=0;j<x;j++){
            temp = img[3*(i*x+j)];
            img[3*(i*x+j)] = img[3*(i*x+j)+2];
            img[3*(i*x+j)+2] = temp;
        }
    }
}

得到的结果:除了显示速度较慢外其他都一样

 

转载于:https://www.cnblogs.com/kylehz/p/4489605.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值