用C++处理BMP图像

实验目的:

利用c/c++ 作为编程环境进行图像处理的编程实践,掌握Windows下的BMP图像的存储格式和编程方法。先用C语言熟悉编程环境进行图像的简单处理。

实验要求:

掌握Windows 下的BMP图像的存储格式和基本的处理方法;

实验指导

一、BMP文件结构

二、  BMP图像文件的读写

三、显示图像的数据

   对于读入的图像文件,显示位图数据(选择一部分区域显示即可)。用256色或256级灰度图像进行验证。有两种显示方式:从上到下,从下到上。自己验证。

 

用C++处理BMP图像

用C++处理BMP图像

四、计算图像的直方图(0的不显示;每行最大显示50,直方图先归一化,再乘以50)

对于256级灰度级的图像进行计算。存入一个256元素的数组中,并显示其直方图数据。示意图显示方式:用行表示灰度级,在列上用“*”的多少表示直方图数据的大小。(数据为0的不显示,如果值太大,按比例缩小一下)

用C++处理BMP图像

用C++处理BMP图像

 

五、图像的增亮或减暗

输入一个数字,如果是正数对图像进行增亮,如果是负数对图像进行减暗。

用其他软件进行查看,源图像和被增亮或减暗的图像进行对比,是不是达到了预想的效果。

 

六、main() 函数的要求

main()函数将指定BMP文件读入内存,将图像信息打印输出,最后又原样存入指定文件中。并进行计算需要的数据。

界面:

必做:

0----------结束

1----------读图像8/24位)

2-----------写图像8/24位)

3-----------显示图像数据(1行到10行,1列到10列,10*10的大小)8/24位)

4-----------计算直方图(100-200之间的灰度,1-10行,1-10列,10*10的大小)(8)

5-----------对图像进行增亮或减暗(如加上50或减去50等)(8)

6-----------图像反色8/24位)

选做:

7-----------彩色图变成灰度图(8/24位)

8-----------显示调色板(8位)

9-----------24位彩色图像转换为8位灰度图像

10-----------24位彩色图像转换为8位彩色图像

用户界面

用C++处理BMP图像

 

显示图像数据

用C++处理BMP图像

 

计算直方图(8位图像)

仅仅使用一个通道:rgbBlue

蓝 灰度192

红 灰度64

用C++处理BMP图像

 

调整图像亮度

用C++处理BMP图像

 

图像反色

用C++处理BMP图像

代码:

#include<iostream>
#include<windows.h>
#include <fstream>

using namespace std;

unsigned char *pBmpBuf;//读入图像数据的指针
int bmpWidth;//图像的宽
int bmpHeight;//图像的高
RGBQUAD* pColorTable;//颜色表指针
int biBitCount;//图像类型,每像素位数  

char readPath[] = "1.BMP";
char writePath[] = "2.BMP";

double pixelCount;

bool readBmp(char *bmpName)
{
    //二进制读方式打开指定的图像文件 
    FILE* fp = fopen(bmpName, "rb");
    if (fp == 0) return 0;
    //跳过位图文件头结构BITMAPFILEHEADER 
    fseek(fp, sizeof(BITMAPFILEHEADER), 0);
    //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中 
    BITMAPINFOHEADER head;
    fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);
    //获取图像宽、高、每像素所占位数等信息 
    bmpWidth = head.biWidth;
    bmpHeight = head.biHeight;
    biBitCount = head.biBitCount;
    //定义变量,计算图像每行像素所占的字节数(必须是4的倍数) 
    int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
    //灰度图像有颜色表,且颜色表表项为256 
    if (biBitCount == 8) {
        //申请颜色表所需要的空间,读颜色表进内存 
        pColorTable = new RGBQUAD[256];
        fread(pColorTable, sizeof(RGBQUAD), 256, fp);
    }
    //申请位图数据所需要的空间,读位图数据进内存 
    pBmpBuf = new unsigned char[lineByte * bmpHeight];
    fread(pBmpBuf, 1, lineByte * bmpHeight, fp);
    cout<<"像素:"<<pixelCount<<endl;
    //关闭文件 
    fclose(fp);
    return 1;
}

bool saveBmp(char *bmpName,unsigned char* imgBuf, int width, int height,int biBitCount, RGBQUAD* pColorTable)
{

    //如果位图数据指针为0,则没有数据传入,函数返回 
    if (!imgBuf)
        return 0;
    //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0 
    int colorTablesize = 0;
    if (biBitCount == 8)
        colorTablesize = 1024;
    //待存储图像数据每行字节数为4的倍数 
    int lineByte = (width * biBitCount / 8 + 3) / 4 * 4;
    //以二进制写的方式打开文件 
    FILE* fp = fopen(bmpName, "wb");
    if (fp == 0) return 0;
    //申请位图文件头结构变量,填写文件头信息 
    BITMAPFILEHEADER fileHead;
    fileHead.bfType = 0x4D42;//bmp类型 
    //bfSize是图像文件4个组成部分之和 
    fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
        + colorTablesize + lineByte * height;
    fileHead.bfReserved1 = 0;
    fileHead.bfReserved2 = 0;
    //bfOffBits是图像文件前3个部分所需空间之和 
    fileHead.bfOffBits = 54 + colorTablesize;
    //写文件头进文件 
    fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
    //申请位图信息头结构变量,填写信息头信息 
    BITMAPINFOHEADER head;
    head.biBitCount = biBitCount;
    head.biClrImportant = 0;
    head.biClrUsed = 0;
    head.biCompression = 0;
    head.biHeight = height;
    head.biPlanes = 1;
    head.biSize = 40;
    head.biSizeImage = lineByte * height;
    head.biWidth = width;
    head.biXPelsPerMeter = 0;
    head.biYPelsPerMeter = 0;
    //写位图信息头进内存 
    fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);
    //如果灰度图像,有颜色表,写入文件 
    if (biBitCount == 8)
        fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
    //写位图数据进文件 
    fwrite(imgBuf, height * lineByte, 1, fp);
    //关闭文件 
    fclose(fp);
    cout<<"图像已保存"<<endl; 
    return 1;
}

int outBMP(char *bmpName)
{
     //二进制读方式打开指定的图像文件 
    FILE* fp = fopen(bmpName, "rb");
    if (fp == 0) return 0;
    //跳过位图文件头结构BITMAPFILEHEADER 
    fseek(fp, sizeof(BITMAPFILEHEADER), 0);
    //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中 
    BITMAPINFOHEADER head;
    fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);
    //获取图像宽、高、每像素所占位数等信息 
    bmpWidth = head.biWidth;
    bmpHeight = head.biHeight;
    biBitCount = head.biBitCount;

    pixelCount=bmpWidth*bmpHeight; 
    //cout<<"像素:"<<pixelCount<<endl;
    //定义变量,计算图像每行像素所占的字节数(必须是4的倍数) 
    int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
    //灰度图像有颜色表,且颜色表表项为256 
    if (biBitCount == 8) {
        //申请颜色表所需要的空间,读颜色表进内存 
        pColorTable = new RGBQUAD[256];
        fread(pColorTable, sizeof(RGBQUAD), 256, fp);
    }
    //申请位图数据所需要的空间,读位图数据进内存 
    pBmpBuf = new unsigned char[lineByte * bmpHeight];
    fread(pBmpBuf, 1, lineByte * bmpHeight, fp);

    double tmp[100][100],max=0; 
    for (int i = 0; i < 100; i++)
        for (int t = 0; t < 100; t++)
            tmp[i][t] = pBmpBuf[i * bmpHeight + t * lineByte]; 


    for (int i = 0; i < 100; i++)
    { 
        for (int t = 0; t < 100; t++)
            cout << tmp[i][t] << " ";
        cout << endl;
        //关闭文件 
    fclose(fp);
    return 1;
    }
}



void printChart(int i,double grayFrequency)
{
    double grayCount=grayFrequency*50;
    cout<<i<<" "<<int(grayCount)<<" ";
    for(int j=1;j<=int(grayCount);j++)
    {
        cout<<"*";
        if(j==50)break;
     }
    cout<<endl;
}

int Histogram(char *bmpName,int biBitCount)
{
    if(biBitCount!=8)
    {
        cout<<"图片不是8位!"<<endl;
        cout<<biBitCount;
        system("pause");return 0;   
    }

    BITMAPFILEHEADER bmpFileHeader;
    BITMAPINFOHEADER bmpInfoHeader;
    RGBQUAD bmpColorTable[256];
    BYTE bmpValue[500 * 500];
    FILE *fp;
    //打开lena.bmp图像文件
    fp = fopen(bmpName, "rb");
    //读取图像信息
    fread(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
    fread(&bmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
    fread(bmpColorTable, sizeof(RGBQUAD), 256, fp);
    bmpWidth = bmpInfoHeader.biWidth;
    bmpHeight = bmpInfoHeader.biHeight; 
    pixelCount=bmpWidth*bmpHeight; 
    fread(bmpValue, 1,pixelCount, fp);
    cout<<"像素:"<<pixelCount<<endl;
    //将图像灰度值存入一位数组中
    int grayValue[500 * 500] = { 0 };
    for (int i = 0; i < pixelCount; i++)
    {
        grayValue[i] = bmpColorTable[bmpValue[i]].rgbBlue;
    }
    //统计直方图 
    int grayCount[256] = { 0 };
    double grayFrequency[256] = { 0.0 };
    for (int i = 0; i < pixelCount; i++)
    {
        grayCount[grayValue[i]]++;
    }
    for (int i = 0; i < 256; i++)
    {
        if (grayCount[i])
        {
            grayFrequency[i] = grayCount[i] / pixelCount;
            printChart(i,grayFrequency[i]);
            //printf("灰度值%3d 频数为%6d 频率为%fn", i, grayCount[i], grayFrequency[i]);
        }   
    }
    //关闭图像文件
    fclose(fp);
}

int SetColor(int i,RGBQUAD* &pColorTable,int delta)
{
    if(pColorTable[i].rgbBlue+delta<0)pColorTable[i].rgbBlue=0;
    else    pColorTable[i].rgbBlue+=delta;
    if(pColorTable[i].rgbGreen+delta<0)pColorTable[i].rgbGreen=0;
    else    pColorTable[i].rgbGreen+=delta; 
    if(pColorTable[i].rgbRed+delta<0)pColorTable[i].rgbRed=0;
    else    pColorTable[i].rgbRed+=delta;
    if(pColorTable[i].rgbBlue+delta>255)pColorTable[i].rgbBlue=255;
    else    pColorTable[i].rgbBlue+=delta;
    if(pColorTable[i].rgbGreen+delta>255)pColorTable[i].rgbGreen=255;
    else    pColorTable[i].rgbGreen+=delta; 
    if(pColorTable[i].rgbRed+delta>255)pColorTable[i].rgbRed=255;
    else    pColorTable[i].rgbRed+=delta; 
}

int Lightness(int biBitCount,RGBQUAD* &pColorTable)
{
    if(biBitCount!=8)
    {
        cout<<"图片不是8位!"<<endl;
        system("pause");return 0;   
    }
    int delta=0;
    cout<<"请输入修改亮度的参数:";
    cin>>delta;
    for(int i=0;i<=255;i++)
    {
        SetColor(i,pColorTable,delta);
    }
    saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
}

int SetColor2(int i,RGBQUAD* &pColorTable)
{
    pColorTable[i].rgbBlue=255-pColorTable[i].rgbBlue;
    pColorTable[i].rgbGreen=255-pColorTable[i].rgbGreen;
    pColorTable[i].rgbRed=255-pColorTable[i].rgbRed;
}

int invertColor(RGBQUAD* &pColorTable)
{
    for(int i=0;i<=255;i++)
    {
        SetColor2(i,pColorTable);
    }
    saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
}

void printMenu()
{
    cout<<"------------------------------------------------------------------"<<endl; 
    cout<<"Menu"<<endl;
    cout<<"1)读图像(8/24位)"<<endl;
    cout<<"2)写图像(8/24位)"<<endl;
    cout<<"3)显示图像数据(1行到10行,1列到10列,10*10的大小)(8/24位)"<<endl;
    cout<<"4)计算直方图(100-200之间的灰度,1-10行,1-10列,10*10的大小)(8位)"<<endl;
    cout<<"5)对图像进行增亮或减暗(如加上50或减去50等)(8位)"<<endl;
    cout<<"6)图像反色(8/24位)"<<endl;
    cout<<"7)彩色图变成灰度图(8/24位)"<<endl;
    cout<<"8)显示调色板(8位)"<<endl;
    cout<<"9)24位彩色图像转换为8位灰度图像"<<endl;
    cout<<"0)24位彩色图像转换为8位彩色图像"<<endl;
    cout<<"a)退出"<<endl;
    cout<<"------------------------------------------------------------------"<<endl; 
    char ch;
    cin>>ch;
    switch(ch) 
    {
        case '1':   
                    //用一个函数,把指定BMP文件读入内存 
                    readBmp(readPath);system("cls");
                    cout<<"------------------------------------------------------------------"<<endl; 
                    cout<<"状态:"; 
                    cout<<"已读入图像"<<endl; 
                    break;

        case '2':   
                    saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
                    //清除缓冲区,p和pColorTable是全局变量,在文件读入时申请的空间 
                    delete[]pBmpBuf;
                    if (biBitCount == 8)
                        delete[]pColorTable;
                    system("cls");
                    cout<<"------------------------------------------------------------------"<<endl; 
                    cout<<"状态:"; 
                    cout<<"已写入图像"<<endl; 
                    break;
        case '3':   
                    system("cls");
                    cout<<"------------------------------------------------------------------"<<endl; 
                    cout<<"状态:"; 
                    cout<<"显示图像数据"<<endl; 
                    outBMP(readPath);
                    //pixelShow(); 
                    break;
        case '4':   system("cls");
                    cout<<"------------------------------------------------------------------"<<endl; 
                    cout<<"状态:"; 
                    cout<<"显示直方图"<<endl; 
                    Histogram(readPath,biBitCount);
                    break;
        case '5':   system("cls");
                    cout<<"------------------------------------------------------------------"<<endl; 
                    cout<<"状态:"; 
                    cout<<"调整亮度"<<endl; 
                    Lightness(biBitCount,pColorTable); 
                    break;
        case '6':   system("cls");
                    cout<<"------------------------------------------------------------------"<<endl; 
                    cout<<"状态:"; 
                    cout<<"反色"<<endl; 
                    invertColor(pColorTable);
                    break;
        case '7':break;
        case '8':break;
        case '9':break;
        case '0':   system("cls");
                    cout<<"状态:"; 
                    printf("width=%d,height=%d, biBitCount=%d/n", bmpWidth, bmpHeight, biBitCount);
                    cout<<endl;
                    break;
        case 'a':break;
    }
}


int main()
{
    while(1)
    {
        printMenu();
    }
    return 0;
}

 

原文链接: https://www.cnblogs.com/haiyue-csdn/p/14013906.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    用C++处理BMP图像

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/338038

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午11:25
下一篇 2023年3月1日 下午11:25

相关推荐