C语言实现对BMP文件的单通道图像以及灰度图提取

任务要求:

打开BMP文件,转存成单通道图像,并重新量化为0.5及0.25灰度范围或其他指定灰度范围的图像

结果预览:

 源码(附注释):

#include<stdio.h>
#include<math.h>
#include<windows.h>

/*
FILE *fp = fopen("./image_file/image.bmp", "rb");        //读写权限
fseek(fp, sizeof(BITMAPFILEHEADER), 0);        //文件,指针偏移量(字节),位置(0-文件开头,1-当前位置,2-文件末尾)
fread(&head, 40, 1, fp);        //内存地址,每个数据项字节大小,每个数据项字节个数,输入流
fwrite(&bfhead, 14, 1, fp_gray);    //被写入的数组指针,写入元素大小(字节),元素个数,输出流
fclose(fp);        //关闭文件
*/

int main(int argc, char* argv[]) {
    int bmpHeight;
    int bmpWidth;
    unsigned char *pBmpBuf;
    RGBQUAD *pColorTable;
    int biBitCount;

    //读文件
    FILE *fp = fopen("./image_file/image.bmp", "rb");        //读写权限
    if (fp == 0)
        return 0;
    fseek(fp, sizeof(BITMAPFILEHEADER), 0);        //文件,指针偏移量(字节),从文件开头开始

    BITMAPINFOHEADER head;
    fread(&head, 40, 1, fp);        //内存地址,每个数据项字节大小,每个数据项字节个数,输入流
    bmpHeight = head.biHeight;
    bmpWidth = head.biWidth;
    biBitCount = head.biBitCount;

    fseek(fp, sizeof(RGBQUAD), 1);

    int LineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;        //保证每一行字节数都为4的整数倍
    pBmpBuf = new unsigned char[LineByte*bmpHeight];
    fread(pBmpBuf, LineByte*bmpHeight, 1, fp);
    fclose(fp);


    //通道操作
    FILE *fp_gray = fopen("./image_file/gray.bmp", "wb");
    FILE *fp_r = fopen("./image_file/r.bmp", "wb");
    FILE *fp_g = fopen("./image_file/g.bmp", "wb");
    FILE *fp_b = fopen("./image_file/b.bmp", "wb");


    if (fp_gray == 0 || fp_r == 0 || fp_g == 0 || fp_b == 0)
        return 0;
    int LineByte1 = (bmpWidth * 8 / 8 + 3) / 4 * 4;

    //修改文件头,其中有两项需要修改,分别为bfSize和bfOffBits
    BITMAPFILEHEADER bfhead;
    bfhead.bfType = 0x4D42;
    bfhead.bfSize = 14 + 40 + 256 * sizeof(RGBQUAD) + LineByte1 * bmpHeight;        //修改文件大小
    bfhead.bfReserved1 = 0;
    bfhead.bfReserved2 = 0;
    bfhead.bfOffBits = 14 + 40 + 256 * sizeof(RGBQUAD);        //修改偏移字节数
    fwrite(&bfhead, 14, 1, fp_gray);    //将修改后的文件头存入fp_gray;
    fwrite(&bfhead, 14, 1, fp_r);
    fwrite(&bfhead, 14, 1, fp_g);
    fwrite(&bfhead, 14, 1, fp_b);

    /*    
    修改信息头,其中有两项需要修改
    一个是biBitCount:真彩图为24 ,应改成8;
    另一个是biSizeImage:由于每像素所占位数的变化,所以位图数据的大小发生变化
    */
    BITMAPINFOHEADER head1;
    head1.biBitCount = 8;    //更改每像素的位数
    head1.biClrImportant = 0;
    head1.biCompression = 0;
    head1.biClrUsed = 0;
    head1.biHeight = bmpHeight;
    head1.biWidth = bmpWidth;
    head1.biPlanes = 1;
    head1.biSize = 40;
    head1.biSizeImage = LineByte1 * bmpHeight;        //修改位图数据的大小
    head1.biXPelsPerMeter = 0;
    head1.biYPelsPerMeter = 0;
    fwrite(&head1, 40, 1, fp_gray);        //将修改后的信息头存入fp_gray;
    fwrite(&head1, 40, 1, fp_r);
    fwrite(&head1, 40, 1, fp_g);
    fwrite(&head1, 40, 1, fp_b);

    pColorTable = new RGBQUAD[256];
    for (int i = 0; i < 256; i++) {
        pColorTable[i].rgbRed = i;
        pColorTable[i].rgbGreen = i;
        pColorTable[i].rgbBlue = i;            //使颜色表里的B、G、R分量都相等,且等于索引值
    }
    fwrite(pColorTable, sizeof(RGBQUAD), 256, fp_gray);            //将颜色表写入fp_gray;
    fwrite(pColorTable, sizeof(RGBQUAD), 256, fp_r);
    fwrite(pColorTable, sizeof(RGBQUAD), 256, fp_g);
    fwrite(pColorTable, sizeof(RGBQUAD), 256, fp_b);

    //写位图数据
    unsigned char *pBmpBuf1, *pBmpBuf2, *pBmpBuf3, *pBmpBuf4;
    pBmpBuf1 = new unsigned char[LineByte1*bmpHeight];
    pBmpBuf2 = new unsigned char[LineByte1*bmpHeight];
    pBmpBuf3 = new unsigned char[LineByte1*bmpHeight];
    pBmpBuf4 = new unsigned char[LineByte1*bmpHeight];
    for (int i = 0; i < bmpHeight; i++) {
        for (int j = 0; j < bmpWidth; j++) {
            unsigned char *pb1, *pb_gray, *pb_r, *pb_g, *pb_b;

            pb1 = pBmpBuf + i * LineByte + j * 3;

            int y = *(pb1 + 2)*0.299 + *(pb1 + 1)*0.587 + *(pb1)*0.114;        //将每一个像素都按公式y=R*0.299+G*0.587+B*0.114进行转化
    //        y = y / 2;        //0.5
    //        y = y / 4;        //0.25
            y = y / 16;
            int r = *(pb1 + 2) * 1;
            int g = *(pb1 + 1) * 1;
            int b = *(pb1) * 1;

            pb_gray = pBmpBuf1 + i * LineByte1 + j;
            *pb_gray = y;
            pb_r = pBmpBuf2 + i * LineByte1 + j;
            *pb_r = r;
            pb_g = pBmpBuf3 + i * LineByte1 + j;
            *pb_g = g;
            pb_b = pBmpBuf4 + i * LineByte1 + j;
            *pb_b = b;

        }
    }

    fwrite(pBmpBuf1, LineByte1*bmpHeight, 1, fp_gray);
    fwrite(pBmpBuf2, LineByte1*bmpHeight, 1, fp_r);
    fwrite(pBmpBuf3, LineByte1*bmpHeight, 1, fp_g);
    fwrite(pBmpBuf4, LineByte1*bmpHeight, 1, fp_b);


    for (int i = 0; i < bmpHeight; i++) {
        for (int j = 0; j < bmpWidth / 2; j++) {
            unsigned char *pb1, *pb_gray, *pb_r, *pb_g, *pb_b;

            pb1 = pBmpBuf + i * LineByte + j * 3;

            int y = *(pb1 + 2)*0.299 + *(pb1 + 1)*0.587 + *(pb1)*0.114;        //将每一个像素都按公式y=R*0.299+G*0.587+B*0.114进行转化
    //        y = y / 2;        //0.5
    //        y = y / 4;        //0.25
            y = y / 16;
            int r = *(pb1 + 2) * 1;
            int g = *(pb1 + 1) * 1;
            int b = *(pb1) * 1;

            pb_gray = pBmpBuf1 + i * LineByte1 + j;
            *pb_gray = y;
            pb_r = pBmpBuf2 + i * LineByte1 + j;
            *pb_r = r;
            pb_g = pBmpBuf3 + i * LineByte1 + j;
            *pb_g = g;
            pb_b = pBmpBuf4 + i * LineByte1 + j;
            *pb_b = b;

        }
    }

    fclose(fp_gray);
    fclose(fp_r);
    fclose(fp_g);
    fclose(fp_b);

    system("pause");
    return 0;
}

 

原文地址:https://www.cnblogs.com/wjwjs/p/15325190.html