我已经在图像处理上工作了一段时间,我注意到了奇怪的事情。 我正在阅读一个BMP文件,使用简单的方法,如ReadFile和东西,并使用微软的BMP结构。 这是代码:
ReadFile(_bmpFile,&bmpfh,sizeof(bfh),&data,NULL);
ReadFile(_bmpFile, &bmpih, sizeof(bih), &data, NULL);
imagesize = bih.biWidth*bih.biHeight;
image = new RGBQUAD[imagesize];
ReadFile(_bmpFile,image, imagesize*sizeof(RGBQUAD),&written,NULL);
这就是我读取文件然后使用简单的for循环将其转换为灰度的方法。
for (int i = 0; i < imagesize; i++)
{
RED = image[i].rgbRed;
GREEN = image[i].rgbGreen;
BLUE = image[i].rgbBlue;
avg = (RED + GREEN + BLUE ) / 3;
image[i].rgbRed = avg;
image[i].rgbGreen = avg;
image[i].rgbBlue = avg;
}
现在,当我使用以下代码编写文件时:
#pragma pack(push, 1)
WriteFile(_bmpFile, &bmpfh, sizeof(bfh), &data, NULL);
WriteFile(_bmpFile, &bmpih, sizeof(bih), &data, NULL);
WriteFile(_bmpFile, image, imagesize*sizeof(RGBQUAD), &written, NULL);
#pragma pack(pop)
文件越来越大(30MB - > 40MB)。
它发生的原因是因为我使用的是RGBQUAD而不是RGBTRIPLE,但是如果我使用的是RGBTRIPLE,我将小图片转换为 灰度 - 创建后无法打开图片(说它不在正确的结构中)。
文件大小缺少一个字节(1174kb和1173kb之后)
之前是否有人见过这种情况(只会出现小图片)?
答案 0 :(得分:3)
在BMP文件中,必须填充每条扫描线,以便下一条扫描线在32位边界上开始。如果每个像素执行32位,则会自动执行此操作,但如果每个像素使用24位,则需要添加代码才能显式执行此操作。
答案 1 :(得分:2)
你忽略了步幅(Jerry的评论)和位图的像素格式。从文件大小增加来看,这是24bpp,你写的就好像是32bpp。您的灰度转换错误,人眼对红色,绿色和蓝色不敏感。
考虑使用GDI +,您在代码中使用#include <gdiplus.h>
来使用Bitmap类。它的LockBits()方法使您可以访问位图位。 ColorMatrixEffect类允许您在单个操作中应用颜色转换。检查this answer以获取获得灰度图像所需的颜色矩阵。 MSDN文档start here。
答案 2 :(得分:0)
BMP中的每个水平行必须是4个字节长的倍数。
如果像素数据不占用4个字节的倍数,则在行的末尾添加0x00个字节。对于24-bpp图像,每行的字节数是(imageWidth * 3 + 3)&amp; 〜3。填充字节数为((imageWidth * 3 + 3)&amp; ~3) - (imageWidth * 3)。
这是由immibis回答的。
我想补充说,数组的大小是((imageWidth * 3 + 3)&amp; ~3)* imageHeight。 我希望这有帮助