c语言将24位的bmp图片转为8位灰色,这个读24位bmp的程序有什么问题呢?

时间: 2024-04-28 11:21:17 浏览: 18
在将24位的BMP图片转为8位灰度图片时,需要将RGB三个分量转为一个灰度值,一般采用下面的公式进行转换: Gray = 0.299 * R + 0.587 * G + 0.114 * B 其中,R、G、B分别为红、绿、蓝三个分量的值,Gray为转换后的灰度值。 在读取24位BMP图片时,每个像素点占用3个字节,分别代表红、绿、蓝三个分量。因此,在读取24位BMP图片时,需要注意以下几个问题: 1. BMP图片一般是按行存储的,每行的字节数需要进行计算,不能简单地认为是图片的宽度乘以3。 2. 读取每个像素点时,需要注意字节序问题,有些CPU是大端模式,有些是小端模式。 3. 在转换为灰度图像后,需要将每个像素点的值存储到8位灰度BMP图片中,这里也需要注意字节序问题。 总之,在读取24位BMP图片并转换为8位灰度图像时,需要注意字节序问题和每行的字节数计算问题。
相关问题

c语言将24位的bmp图片转为8位的bmp图片

下面是一个将24位bmp图片转为8位bmp图片的C语言代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #pragma pack(2) // 结构体按2字节对齐 // BMP文件头 typedef struct { char bfType[2]; // 文件类型,必须为BM int bfSize; // 文件大小,包括文件头、位图信息头、调色板和位图数据 short bfReserved1; // 保留字段,必须为0 short bfReserved2; // 保留字段,必须为0 int bfOffBits; // 从文件头到位图数据的偏移量,单位为字节 } BMPFileHeader; // BMP位图信息头 typedef struct { int biSize; // 结构体大小,必须为40 int biWidth; // 图像宽度,单位为像素 int biHeight; // 图像高度,单位为像素 short biPlanes; // 必须为1 short biBitCount; // 每个像素所需位数,必须为8 int biCompression; // 压缩类型,必须为0 int biSizeImage; // 位图数据大小,单位为字节 int biXPelsPerMeter; // 水平分辨率,单位为像素/米 int biYPelsPerMeter; // 垂直分辨率,单位为像素/米 int biClrUsed; // 实际使用的颜色表中的颜色数,0表示使用全部颜色 int biClrImportant; // 对图象显示有重要影响的颜色数,0表示都重要 } BMPInfoHeader; // BMP调色板 typedef struct { unsigned char rgbBlue; // 蓝色分量 unsigned char rgbGreen; // 绿色分量 unsigned char rgbRed; // 红色分量 unsigned char rgbReserved; // 保留字段,必须为0 } RGBQuad; int main() { FILE *fpIn, *fpOut; BMPFileHeader fileHeader; BMPInfoHeader infoHeader; RGBQuad *palette = NULL; unsigned char *pixelData24 = NULL, *pixelData8 = NULL; int rowSize24, rowSize8, padding24, padding8; int width, height, i, j, k; // 读取24位bmp图片文件 fpIn = fopen("input.bmp", "rb"); if (fpIn == NULL) { printf("Open file failed!\n"); return -1; } fread(&fileHeader, sizeof(BMPFileHeader), 1, fpIn); fread(&infoHeader, sizeof(BMPInfoHeader), 1, fpIn); // 获取图片宽度、高度、每行像素所占字节数、调色板大小 width = infoHeader.biWidth; height = infoHeader.biHeight; rowSize24 = width * 3; padding24 = (rowSize24 % 4) ? (4 - rowSize24 % 4) : 0; // 分配内存,读取调色板和像素数据 palette = (RGBQuad*)malloc(sizeof(RGBQuad) * 256); pixelData24 = (unsigned char*)malloc(sizeof(unsigned char) * (rowSize24 + padding24) * height); pixelData8 = (unsigned char*)malloc(sizeof(unsigned char) * width * height); if (palette == NULL || pixelData24 == NULL || pixelData8 == NULL) { printf("Memory allocation failed!\n"); return -1; } fread(palette, sizeof(RGBQuad), 256, fpIn); fread(pixelData24, sizeof(unsigned char), (rowSize24 + padding24) * height, fpIn); fclose(fpIn); // 计算8位bmp图片的每行像素所占字节数和调色板大小 rowSize8 = ((width + 3) / 4) * 4; padding8 = rowSize8 - width; // 将24位像素转换为8位像素 for (i = 0; i < height; i++) { for (j = 0, k = 0; j < rowSize24; j += 3, k++) { int gray = (int)(0.299 * pixelData24[i * (rowSize24 + padding24) + j + 2] + 0.587 * pixelData24[i * (rowSize24 + padding24) + j + 1] + 0.114 * pixelData24[i * (rowSize24 + padding24) + j]); pixelData8[i * rowSize8 + k] = (unsigned char)gray; } // 填充空白字节 for (j = 0; j < padding8; j++) { pixelData8[i * rowSize8 + k + j] = 0; } } // 写入8位bmp图片文件 fpOut = fopen("output.bmp", "wb"); if (fpOut == NULL) { printf("Create file failed!\n"); return -1; } fwrite(&fileHeader, sizeof(BMPFileHeader), 1, fpOut); fwrite(&infoHeader, sizeof(BMPInfoHeader), 1, fpOut); fwrite(palette, sizeof(RGBQuad), 256, fpOut); fwrite(pixelData8, sizeof(unsigned char), rowSize8 * height, fpOut); fclose(fpOut); // 释放内存 free(palette); free(pixelData24); free(pixelData8); return 0; } ``` 该程序先读取24位bmp图片文件的文件头、位图信息头、调色板和像素数据,然后将24位像素转换为8位像素,并写入8位bmp图片文件的文件头、位图信息头、调色板和像素数据。注意,这里使用了灰度化公式将RGB三个通道的亮度值加权平均,然后取整得到灰度值。同时还需要考虑到调色板等其他因素。

c语言将24位的bmp图片转为8位的bmp图片 示例代码

以下是一个将24位BMP图片转换为8位BMP图片的示例代码。这里使用了Windows API来读取和写入BMP文件,因此需要包含Windows.h头文件。 ``` #include <Windows.h> int main() { // 打开24位BMP文件 HANDLE hFile = CreateFile(L"input.bmp", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("无法打开文件\n"); return 1; } // 读取BMP文件头信息 BITMAPFILEHEADER bmpFileHeader; DWORD dwBytesRead; if (!ReadFile(hFile, &bmpFileHeader, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL) || dwBytesRead != sizeof(BITMAPFILEHEADER)) { printf("无法读取文件头\n"); CloseHandle(hFile); return 1; } // 读取BMP信息头信息 BITMAPINFOHEADER bmpInfoHeader; if (!ReadFile(hFile, &bmpInfoHeader, sizeof(BITMAPINFOHEADER), &dwBytesRead, NULL) || dwBytesRead != sizeof(BITMAPINFOHEADER)) { printf("无法读取信息头\n"); CloseHandle(hFile); return 1; } // 只支持24位BMP if (bmpInfoHeader.biBitCount != 24) { printf("不支持的位数\n"); CloseHandle(hFile); return 1; } // 读取调色板信息 RGBQUAD palette[256]; if (!ReadFile(hFile, palette, sizeof(RGBQUAD) * 256, &dwBytesRead, NULL) || dwBytesRead != sizeof(RGBQUAD) * 256) { printf("无法读取调色板\n"); CloseHandle(hFile); return 1; } // 计算调色板中各颜色的灰度值 BYTE grayTable[256]; for (int i = 0; i < 256; i++) { grayTable[i] = (BYTE)(0.299 * palette[i].rgbRed + 0.587 * palette[i].rgbGreen + 0.114 * palette[i].rgbBlue); } // 读取像素数据 BYTE* pixelData = (BYTE*)malloc(bmpInfoHeader.biSizeImage); if (!ReadFile(hFile, pixelData, bmpInfoHeader.biSizeImage, &dwBytesRead, NULL) || dwBytesRead != bmpInfoHeader.biSizeImage) { printf("无法读取像素数据\n"); CloseHandle(hFile); free(pixelData); return 1; } // 关闭24位BMP文件 CloseHandle(hFile); // 创建8位BMP文件 HANDLE hNewFile = CreateFile(L"output.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hNewFile == INVALID_HANDLE_VALUE) { printf("无法创建文件\n"); free(pixelData); return 1; } // 写入BMP文件头信息 BITMAPFILEHEADER newBmpFileHeader = bmpFileHeader; newBmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256 + bmpInfoHeader.biWidth * bmpInfoHeader.biHeight; newBmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256; if (!WriteFile(hNewFile, &newBmpFileHeader, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL) || dwBytesRead != sizeof(BITMAPFILEHEADER)) { printf("无法写入文件头\n"); CloseHandle(hNewFile); free(pixelData); return 1; } // 写入BMP信息头信息 BITMAPINFOHEADER newBmpInfoHeader = bmpInfoHeader; newBmpInfoHeader.biBitCount = 8; newBmpInfoHeader.biClrUsed = 256; newBmpInfoHeader.biSizeImage = bmpInfoHeader.biWidth * bmpInfoHeader.biHeight; if (!WriteFile(hNewFile, &newBmpInfoHeader, sizeof(BITMAPINFOHEADER), &dwBytesRead, NULL) || dwBytesRead != sizeof(BITMAPINFOHEADER)) { printf("无法写入信息头\n"); CloseHandle(hNewFile); free(pixelData); return 1; } // 写入调色板信息 if (!WriteFile(hNewFile, palette, sizeof(RGBQUAD) * 256, &dwBytesRead, NULL) || dwBytesRead != sizeof(RGBQUAD) * 256) { printf("无法写入调色板\n"); CloseHandle(hNewFile); free(pixelData); return 1; } // 将像素数据转换为8位颜色编号,并写入文件 for (int i = 0; i < bmpInfoHeader.biSizeImage; i += 3) { BYTE grayValue = (BYTE)(0.299 * pixelData[i + 2] + 0.587 * pixelData[i + 1] + 0.114 * pixelData[i]); BYTE colorIndex = 0; for (int j = 0; j < 256; j++) { if (grayValue >= grayTable[j]) { colorIndex = j; } else { break; } } if (!WriteFile(hNewFile, &colorIndex, 1, &dwBytesRead, NULL) || dwBytesRead != 1) { printf("无法写入像素\n"); CloseHandle(hNewFile); free(pixelData); return 1; } } // 关闭8位BMP文件 CloseHandle(hNewFile); free(pixelData); return 0; } ``` 这个示例代码中,将24位BMP图片的RGB像素数据转换为灰度值的计算公式采用了常见的"NTSC"标准。实际使用中,可以根据需要使用其他公式。同时,如果需要处理的是其他位数的BMP图片,需要根据其格式进行相应的修改。

相关推荐

最新推荐

recommend-type

C语言中位运算置0操作

这里的 0x01 是一个位掩码,它将第四位设置为1,而其他位设置为0。然后,我们使用按位与 (&) 运算符将 x 与位掩码进行与运算,结果将第四位设置为0。 宏操作 宏操作是指使用 define 语句定义的宏。宏操作可以在...
recommend-type

C语言实现BMP转换JPG的方法

这篇描述提到了一个名为`jpeg.c`的源代码文件,用于在Linux环境下将BMP(位图)格式的图像转换为JPG(联合图像专家组)格式。下面我们将详细探讨这个过程中的关键步骤和技术。 首先,要进行BMP到JPG的转换,我们...
recommend-type

8位bmp图像的读写 代码

在本文中,我们将深入探讨8位BMP图像的读写操作,这是一个基本的图像处理概念,主要涉及到计算机图形学和图像编码领域。8位BMP图像意味着每个像素由8位表示,最多支持256种颜色。以下是关于这个主题的详细说明: ...
recommend-type

c语言中获取整数和浮点数的符号位

但是,这种方法有两个缺点:一是影响效率,二是格式不够简洁美观。因此,我们需要一种更好的方法来获取符号位。 那么,如何获取符号位呢?一种常见的方法是使用移位操作。移位操作可以将符号位移动到右边第一位,...
recommend-type

c语言float类型小数点后位数

C语言 Float 类型小数点后位数 C 语言中的 Float 类型是一种浮点数类型,它用于存储小数点后的数字。Float 类型的小数点后位数是一个重要的概念,它决定了浮点数的精度和范围。在本文中,我们将详细介绍 C 语言中 ...
recommend-type

VMP技术解析:Handle块优化与壳模板初始化

"这篇学习笔记主要探讨了VMP(Virtual Machine Protect,虚拟机保护)技术在Handle块优化和壳模板初始化方面的应用。作者参考了看雪论坛上的多个资源,包括关于VMP还原、汇编指令的OpCode快速入门以及X86指令编码内幕的相关文章,深入理解VMP的工作原理和技巧。" 在VMP技术中,Handle块是虚拟机执行的关键部分,它包含了用于执行被保护程序的指令序列。在本篇笔记中,作者详细介绍了Handle块的优化过程,包括如何删除不使用的代码段以及如何通过指令变形和等价替换来提高壳模板的安全性。例如,常见的指令优化可能将`jmp`指令替换为`push+retn`或者`lea+jmp`,或者将`lodsbyteptrds:[esi]`优化为`moval,[esi]+addesi,1`等,这些变换旨在混淆原始代码,增加反逆向工程的难度。 在壳模板初始化阶段,作者提到了1.10和1.21两个版本的区别,其中1.21版本增加了`Encodingofap-code`保护,增强了加密效果。在未加密时,代码可能呈现出特定的模式,而加密后,这些模式会被混淆,使分析更加困难。 笔记中还提到,VMP会使用一个名为`ESIResults`的数组来标记Handle块中的指令是否被使用,值为0表示未使用,1表示使用。这为删除不必要的代码提供了依据。此外,通过循环遍历特定的Handle块,并依据某种规律(如`v227&0xFFFFFF00==0xFACE0000`)进行匹配,可以找到需要处理的指令,如`push0xFACE0002`和`movedi,0xFACE0003`,然后将其替换为安全的重定位值或虚拟机上下文。 在结构体使用方面,笔记指出壳模板和用户代码都会通过`Vmp_AllDisassembly`函数进行解析,而且0x8和0x10字段通常都指向相同的结构体。作者还提到了根据`pNtHeader_OptionalHeader.Magic`筛选`ESI_Matching_Array`数组的步骤,这可能是为了进一步确定虚拟机上下文的设置。 这篇笔记深入解析了VMP技术在代码保护中的应用,涉及汇编指令的优化、Handle块的处理以及壳模板的初始化,对于理解反逆向工程技术以及软件保护策略有着重要的参考价值。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

【进阶】音频处理基础:使用Librosa

![【进阶】音频处理基础:使用Librosa](https://picx.zhimg.com/80/v2-a39e5c9bff1d920097341591ca8a2dfe_1440w.webp?source=1def8aca) # 2.1 Librosa库的安装和导入 Librosa库是一个用于音频处理的Python库。要安装Librosa库,请在命令行中输入以下命令: ``` pip install librosa ``` 安装完成后,可以通过以下方式导入Librosa库: ```python import librosa ``` 导入Librosa库后,就可以使用其提供的各种函数
recommend-type

python中字典转换成json

在Python中,你可以使用`json`模块将字典转换为JSON格式的字符串。下面是一个简单的示例: ```python import json # 假设我们有一个字典 dict_data = { "name": "John", "age": 30, "city": "New York" } # 使用json.dumps()函数将字典转换为JSON json_string = json.dumps(dict_data) print(json_string) # 输出:{"name": "John", "age": 30, "city": "New York"}
recommend-type

C++ Primer 第四版更新:现代编程风格与标准库

"Cpp Primer第四版中文版(电子版)1" 本书《Cpp Primer》第四版是一本深入浅出介绍C++编程语言的教程,旨在帮助初学者和有经验的程序员掌握现代C++编程技巧。作者在这一版中进行了重大更新,以适应C++语言的发展趋势,特别是强调使用标准库来提高编程效率。书中不再过于关注底层编程技术,而是将重点放在了标准库的运用上。 第四版的主要改动包括: 1. 内容重组:为了反映现代C++编程的最佳实践,书中对语言主题的顺序进行了调整,使得学习路径更加顺畅。 2. 添加辅助学习工具:每章增设了“小结”和“术语”部分,帮助读者回顾和巩固关键概念。此外,重要术语以黑体突出,已熟悉的术语以楷体呈现,以便读者识别。 3. 特殊标注:用特定版式标注关键信息,提醒读者注意语言特性,避免常见错误,强调良好编程习惯,同时提供通用的使用技巧。 4. 前后交叉引用:增加引用以帮助读者理解概念之间的联系。 5. 额外讨论和解释:针对复杂概念和初学者常遇到的问题,进行深入解析。 6. 大量示例:提供丰富的代码示例,所有源代码都可以在线获取,便于读者实践和学习。 本书保留了前几版的核心特色,即以实例教学,通过解释和展示语言特性来帮助读者掌握C++。作者的目标是创作一本清晰、全面、准确的教程,让读者在编写程序的过程中学习C++,同时也展示了如何有效地利用这门语言。 《Cpp Primer》第四版不仅适合C++初学者,也适合想要更新C++知识的老手,它全面覆盖了C++语言的各个方面,包括基础语法、类、模板、STL(Standard Template Library)等,同时引入了现代C++的特性,如智能指针、RAII(Resource Acquisition Is Initialization)、lambda表达式等,使读者能够跟上C++语言的发展步伐,提升编程技能。