2013-10-27 30 views
1

我仍然是C++的noob,我目前正在嘗試創建一個程序,它將256色位圖手動加載到數組中,並打印出每個像素的值CONSOL。看來這些價值觀,大多數時候,是不正確的。當從24位位圖讀取像素時出現奇怪的值

我的其他輸出(例如信息頭內的值)都很好,除了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

是否bmpImage。INFOHEADER.biSizeImage == ImagePixelAmount * sizeof(int); ? –

+2

對古代圖像格式的不懈追求是不可阻擋的,8bpp只在20年前變得至關重要。你的malloc()調用是錯誤的,8bpp圖像中的一個像素是一個字節,而不是'unsigned int'。而一張8bpp圖片有一張顏色表。 –

+0

謝謝你的答案! @PierreEmmanuelLallemant:可悲的是,情況並非如此。 – StirriX

回答

2

您確定您正在閱讀固體純紅色(255,0,0 RGB)BMP嗎?我問,因爲我創建了以下一個程序的輸出:

紅:255綠:0藍:0紅:255綠:0藍:0

紅:0綠:0藍:0紅色:0綠色:255藍色:0

仍然不正確,但更接近您的預期。但是爲什麼第二行錯了?

表示位圖像素的位被打包在行中。每行的大小通過填充四捨五入爲4個字節(32位DWORD)的倍數。 - source

這裏是產生從塗料的摘錄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,所以添加到每個像素行的端部提供了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 
+0

非常感謝,我會把自己讀進填充:) – StirriX