1

我在图像处理方面工作了一段时间,我注意到一些奇怪的事情。我正在读取 BMP 文件,使用 ReadFile 之类的简单方法以及 Microsoft 的 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 之后)

有没有人见过这个(它只出现在小图片上)?

4

3 回答 3

3

在 BMP 文件中,必须填充每条扫描线,以便下一条扫描线从 32 位边界开始。如果您使用每像素 32 位,这会自动发生,但如果您使用每像素 24 位,则需要添加代码来明确执行此操作。

于 2011-03-26T18:02:39.057 回答
2

您忽略了步幅(杰瑞的评论)和位图的像素格式。从文件大小的增加来看,这是 24bpp,你正在写它,就好像它是 32bpp。您的灰度转换是错误的,人眼对红色,绿色和蓝色的敏感度不同。

考虑使用 GDI+,您<gdiplus.h>在代码中 #include 以使用 Bitmap 类。它的 LockBits() 方法使您可以访问位图位。ColorMatrixEffect 类允许您在单个操作中应用颜色转换。检查此答案以获得获得灰度图像所需的颜色矩阵。MSDN 文档从这里开始

于 2011-03-26T18:27:47.270 回答
0

BMP 中的每个水平行的长度必须是 4 字节的倍数。

如果像素数据不占用 4 字节的倍数,则在行尾添加 0x00 字节。对于 24-bpp 图像,每行的字节数为 (imageWidth*3 + 3) & ~3。填充字节数为 ((imageWidth*3 + 3) & ~3) - (imageWidth*3)。

这是由immibis回答的。

我想补充一点,数组的大小是 ((imageWidth*3 + 3) & ~3)*imageHeight. 我希望这有帮助

于 2015-01-17T09:03:15.327 回答