zoukankan      html  css  js  c++  java
  • 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;
    }

     

  • 相关阅读:
    微信表情代码
    SQL四个排名函数(row_number、rank、dense_rank和ntile)的使用
    JS获取URL传过来的参数
    QQ在线咨询代码
    AJAX定时请求数据
    C#模拟登录主动推送信息
    HTML 5实现手机摇一摇的功能
    禁用站点asp运行
    二维码扫描极速版4.0.apk
    .NET Framework4网站 无法运行,提示找不到网络名,IO错误等解决办法
  • 原文地址:https://www.cnblogs.com/wjwjs/p/15325190.html
Copyright © 2011-2022 走看看