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; }