我仍然是c ++中的菜鸟,我目前正在尝试创建一个程序,手动将256色位图加载到数组中,并打印出consol中每个像素的值。似乎这些价值观,大多数时候都是不正确的。
我的其他输出(例如info标头内的值)都很好,除了biSizeImage
,即5字节。难道这不应该是25字节吗?
出于测试目的,我拍摄了两张5 x 5图像。其中一个是全黑的,另一个是全白的
我希望黑色,输出类似于:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
但我得到了:
0 0 0 0 0
0 0 0 0 0
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
对于完全白色的图片,我的结果更加奇怪:
4294967295 255 4294967295 255 4294967295
255 4294967295 255 4294967295 255
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
您可以在下面看到我当前的代码:
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
using namespace std;
#pragma pack(push,1)
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType; // Specifies the type of file. This member must be BM. (0x4D42)
unsigned int bfSize; // Specifies the size of the file, in bytes.
short bfReserved1; // Reserved; must be set to zero.
short bfReserved2; // Reserved; must be set to zero.
unsigned int bfOffBits; // Specifies the byte offset from the BITMAPFILEHEADER structure to the actual bitmap data in the file.
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
unsigned int biSize; // Specifies the number of bytes required by the BITMAPINFOHEADER structure.
int biWidth; // Specifies the width of the bitmap, in pixels.
int biHeight; // Specifies the height of the bitmap, in pixels.
unsigned short biPlanes; // Specifies the number of planes for the target device. This member must be set to 1.
unsigned short biBitCount; // Specifies the number of bits per pixel. This value must be 1,4, 8, or 24.
unsigned int biCompression; // Specifies the type of compression for a compressed bitmap. Itcan be one of the following values: BI_RGB, BI_RLE8, BI_RLE4
unsigned int biSizeImage; // Specifies the size, in bytes, of the image. It is valid to set this member to zero if the bitmap is in the BI_RGB format.
int biXPelsPerMeter; // Specifies the horizontal resolution, in pixels per meter, of the target device for the bitmap.
int biYPelsPerMeter; // Specifies the vertical resolution, in pixels per meter, of the target device for the bitmap.
unsigned int biClrUsed; // Specifies the number of color indexes in the color table actually used by the bitmap.
unsigned int biClrImportant; // Specifies the number of color indexes that are considered important for displaying the bitmap. If this value is zero, all colors are important.
} BITMAPINFOHEADER;
typedef struct tagRGBPIXEL{
unsigned char b;
unsigned char g;
unsigned char r;
} rgbPIXEL;
#pragma pack(pop)
typedef struct tagBITMAP{
BITMAPFILEHEADER FILEHEADER;
BITMAPINFOHEADER INFOHEADER;
rgbPIXEL* IMAGEDATA;
}BITMAP;
void main (){
string sImageLocation = "C:/BMP.bmp";
BITMAP bmpImage;
FILE* fbmpImage = NULL;
unsigned int ImagePixelAmount = 0;
bool bImageLoaded = false;
do{
//Open the image file
fopen_s(&fbmpImage, sImageLocation.c_str(), "rb");
//Check whether the image could be loaded successfully or not
if(fbmpImage == NULL){
cout << "Loading the image file failed!" << " " << endl;
}
if(fbmpImage != NULL){
cout << "Loaded the image file successfully!" << endl;
bImageLoaded = true;
}
cout << endl;
cout << endl;
cout << endl;
//Read the BITMAP FILE HEADER
fseek(fbmpImage, 0, SEEK_SET);
fread(&bmpImage.FILEHEADER, sizeof(BITMAPFILEHEADER), 1, fbmpImage);
//Check if the image is a valid bitmap file
if(bmpImage.FILEHEADER.bfType != 19778){
bImageLoaded = false;
cout << "Image is not a valid Bitmap file!" << endl;
fclose(fbmpImage);
}
}while(bImageLoaded = false);
//Show the information of the BITMAP FILE HEADER in the consol
cout << "Bitmap File Header Data Values:" << endl;
cout << endl;
cout << "Image Type: " << bmpImage.FILEHEADER.bfType << endl;
cout << "Image Size: " << bmpImage.FILEHEADER.bfSize << " Bytes" << endl;
cout << "Reserved: " << bmpImage.FILEHEADER.bfReserved1 << endl;
cout << "Reserved: " << bmpImage.FILEHEADER.bfReserved2 << endl;
cout << "Byte Offset: " << bmpImage.FILEHEADER.bfOffBits << endl;
cout << endl;
cout << endl;
cout << endl;
//Read the BITMAP INFO HEADER
fread(&bmpImage.INFOHEADER, sizeof(BITMAPINFOHEADER), 1, fbmpImage);
cout << "Bitmap Info Header Data Values: " << endl;
cout << endl;
cout << "Size of Bitmap Info Header: " << bmpImage.INFOHEADER.biSize << " Bytes" << endl;
cout << "Width of Bitmap: " << bmpImage.INFOHEADER.biWidth << " Pixel" << endl;
cout << "Height of Bitmap: " << bmpImage.INFOHEADER.biHeight << " Pixel" << endl;
cout << "Size of Image Data: " << bmpImage.INFOHEADER.biHeight << " Bytes" << endl;
cout << "Bit Count: " << bmpImage.INFOHEADER.biBitCount << " Bits Per Pixel" << endl;
cout << "Amount of color indexes: " << bmpImage.INFOHEADER.biClrUsed << endl;
cout << "Compression: " << bmpImage.INFOHEADER.biCompression << endl;
cout << endl;
cout << endl;
cout << endl;
ImagePixelAmount = bmpImage.INFOHEADER.biHeight * bmpImage.INFOHEADER.biWidth;
//Create space in memory and read in pixel data from the image
bmpImage.IMAGEDATA = (rgbPIXEL*)malloc(sizeof(rgbPIXEL) * ImagePixelAmount);
cout << "Memory for image created" << endl;
fseek(fbmpImage, bmpImage.FILEHEADER.bfOffBits, SEEK_SET);
fread(bmpImage.IMAGEDATA, ImagePixelAmount * sizeof(rgbPIXEL), 1, fbmpImage);
fclose(fbmpImage);
//Show the pixel data in the consol in numbers instead of ASCII-symbols
for(int y =0; y < bmpImage.INFOHEADER.biHeight; y++){
for(int x = 0; x < bmpImage.INFOHEADER.biWidth; x++){
cout << "Red: " <<(unsigned int) bmpImage.IMAGEDATA[y * bmpImage.INFOHEADER.biWidth + x].r << " ";
cout << "Green: " <<(unsigned int) bmpImage.IMAGEDATA[y * bmpImage.INFOHEADER.biWidth + x].g << " ";
cout << "Blue: " <<(unsigned int) bmpImage.IMAGEDATA[y * bmpImage.INFOHEADER.biWidth + x].b << " ";
}
cout << endl;
}
cout << endl;
cout << endl;
cout << endl;
cout << "Press any key to quit the programm" << endl;
_getch();
return;
}
更新
根据Hans Passant的说法,我改变了我的代码以加载24位位图。使用红色位图,我假设每个像素的打印值为red = 255, green = 0 and blue = 0
。但是,我收到的每个像素的实际值是red = 237, green = 28 and blue = 36
。对于任何其他图像我都有同样的麻烦。
答案 0 :(得分:2)
你确定你正在阅读纯红色(255,0,0 RGB)BMP吗?我问,因为我创建了一个,你的程序输出如下:
红色:255绿色:0蓝色:0红色:255绿色:0蓝色:0
红色:0绿色:0蓝色:0红色:0绿色:255蓝色:0
仍然不正确,但更接近你的期望。但为什么第二行错了?
表示位图像素的位按行打包。通过填充将每行的大小向上舍入为4个字节(32位DWORD)的倍数。 - source
以下是Paint生成的BMP的摘录:
0000 ff00 00ff 0000 0000 ff00 00ff 0000
是:
00
:绿色(0)
00
:蓝色(0)
ff
:红色(255)
00
:绿色(0)
00
:蓝色(0)
ff
:红色(255)
00
:填充
00
:填充
00
:绿色(0)
00
:蓝色(0)
ff
:红色(255)
00
:绿色(0)
00
:蓝色(0)
ff
:红色(255)
00
:填充
00
:填充
请记住,填充量等于(width * channels) % 4
,在这种情况下为(2 * 3) % 4 = 2
,因此我们将两个填充添加到每行像素的末尾。
我没有时间完全检查你的代码,但我不相信你是在考虑这个填充。请注意,虽然32位(GBRA)BMP没有此填充,因为(width * 4) % 4
始终为0
。
Here is a stand-alone program。我从旧项目中删除了BMP加载的相关部分。您可以在24位BMP文件中查看我在哪里考虑填充。
此外,来自维基百科文章的another example。
修改
忘记提及这是一个2x2红色BMP图像。上面的摘录是像素数组,完整的文件如下:
424d 4600 0000 0000 0000 3600 0000 2800
0000 0200 0000 0200 0000 0100 1800 0000
0000 1000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 ff00 00ff 0000 0000
ff00 00ff 0000