C++ 如何在bmp中逐像素读取

C++ 如何在bmp中逐像素读取,c++,bitmap,rgb,C++,Bitmap,Rgb,我有个问题!我想得到24位位图中每个像素的RGB信息。 到目前为止,我编写了一个代码,它可以获取位图的信息,但是我在获取每个像素的RGB信息时遇到了一个问题。我想把这些信息保存在像素结构的tabel pix中。 你能帮我吗 我把代码放在下面: #include <iostream> #include <fstream> #include <conio.h> using namespace std; #pragma pack(2) struct

我有个问题!我想得到24位位图中每个像素的RGB信息。 到目前为止,我编写了一个代码,它可以获取位图的信息,但是我在获取每个像素的RGB信息时遇到了一个问题。我想把这些信息保存在像素结构的tabel pix中。 你能帮我吗

我把代码放在下面:

     #include <iostream>
#include <fstream>
#include <conio.h>

using namespace std;

#pragma pack(2)

struct BITMAPFILEHEADER             // File header
{ 
  char bfType[2];                   // File type: should be BM ( 0x42 0x4D ) 
  int bfSize;                       // File size in bytes
  short bfReserved1;                // Reserved - for what i have no idea :P 
  short bfReserved2;                // -||-
  int bfOffBits;                    // Offset, adress of the beginning of the information about image (pixels )
};

struct BITMAPINFOHEADER             // Bitmap header
{
  unsigned int biSize;              // Size of this header
  unsigned int biWidth;             // Width of image ( in pixels)
  unsigned int biHeight;            // Height of this image ( in pixels )
  unsigned short biPlanes;          // Numer of color planes, always 1
  unsigned short biBitCount;        // Number of bytes for pixel. Possibility values :1,4,8,16, 24 and 32
  unsigned int biCompression;       // Used compression (0 -none)
  unsigned int biSizeImage;         // Size of image 
  signed int biXPelsPerMeter;       // Horizontal resolution of the image (pixel per meter)
  signed int biYPelsPerMeter;       // Vertical resolution of the image (pixel per meter)
  unsigned int biClrUsed;           // Number of colors in the color palette, or 0 to default to 2^n ( 0- no palette)
  unsigned int biClrImportant;      // Number of important colors used
};



#pragma pack(push, 1)

struct Pixel{
    unsigned int blue;  // or double?
    unsigned int green;
    unsigned int red;
    //unsigned char reserved;
};
#pragma pack(pop)

int main(){

    // Openning the file

    cout << "Openning the file for reading: "<< endl;
    _getch();
    ifstream ifs("moj.bmp", ios::binary);

    if(!ifs){
        cout << " There is no such of file ";
        _getch();
        return 0;   
    } 

    // Reading information about BITMAPFILEHEADER
    char* temp = new char[sizeof(BITMAPFILEHEADER)];
    ifs.read(temp, sizeof(BITMAPFILEHEADER));
    BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER*)(temp);

    cout << "\n FILHEADER\n";
    cout << "\n File type: " << bfh->bfType[0] << bfh->bfType[1] << endl;
    cout << " File size: " << bfh->bfSize << endl;
    cout << " Offset(adress of beggining of the image information): " << bfh->bfOffBits << endl;
    _getch();


    // Reading information about BITMAPINFOHEADER
    temp = new char[sizeof(BITMAPINFOHEADER)];
    ifs.read(temp, sizeof(BITMAPINFOHEADER));
    BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)(temp);

    cout << "\n INFOHEADER\n";
    cout << "\n Header size: " << bih->biSize << endl;
    cout << " Image width: " << bih->biWidth << endl;
    cout << " Image height: " << bih->biHeight << endl;
    cout << " Number of bytes for pixel: " << bih->biBitCount << endl;
    cout << " Used compression: " << bih->biCompression << endl;
    cout << " Image size: " << bih->biSizeImage<< endl;
    cout << " Horizontal resolution: " << bih->biXPelsPerMeter << endl;
    cout << " Vertical resolution: " << bih->biYPelsPerMeter << endl;
    cout << " Number of colors in the color palette: " << bih->biClrUsed << endl;
    cout << " Number of important colors used: " << bih->biClrImportant << endl;
    _getch();

    Pixel** pixs = new Pixel*[bih->biHeight];
    for (int i = 0; i < bih->biHeight ; ++i)
        pixs[i] = new Pixel[bih->biWidth];


    ifs.seekg(bfh->bfOffBits, ios::beg); // bfOffBits points for beginning of the image information


               /* I have no idea how to read pixel after pixel in this moment */


    _getch();

    for (int i = 0; i < bih->biHeight; ++i) 
        delete pixs[i];

    delete pixs;
    delete bfh;
    delete bih;

    return 0;

}
它不起作用。在PIX[i][j]中的这个命令后面有一些垃圾…:/

也许有一些建议?

如果您有偏移量和图像大小,并且您确定图像为24位(每种颜色1字节),则可以逐像素扫描图像缓冲区

uint8_t* pixelTmp = new uint8_t[3];
for (int i = 0; i != imageSize; ++i) {
    ifs.read(pixelTmp, 3);
    pixelTmp[0]; /* is blue 0-255 */
    pixelTmp[1]; /* is green 0-255 */
    pixelTmp[2]; /* is red 0-255 */
}
pixelTmp[0]
的值指定给您自己的蓝色像素,以此类推。

当您有偏移量和图像大小,并且您确定图像为24位(每种颜色1字节)时,您可以逐个像素扫描图像缓冲区

uint8_t* pixelTmp = new uint8_t[3];
for (int i = 0; i != imageSize; ++i) {
    ifs.read(pixelTmp, 3);
    pixelTmp[0]; /* is blue 0-255 */
    pixelTmp[1]; /* is green 0-255 */
    pixelTmp[2]; /* is red 0-255 */
}
pixelTmp[0]
的值分配给您自己的蓝色像素,依此类推……

如您所见,1个像素使用3个字节。这意味着第一个字节为蓝色,第二个为绿色,第三个为红色。您现在应该做的是循环浏览位图文件的其余部分,读取3个单独的字节,并将它们存储在结构中:

char r, g, b;
ifs.read(&b, 1);
ifs.read(&g, 1);
ifs.read(&r, 1);
您可以查看示例1以查看图像行的存储方式。

如您所见,1个像素使用3个字节。这意味着第一个字节为蓝色,第二个为绿色,第三个为红色。您现在应该做的是循环浏览位图文件的其余部分,读取3个单独的字节,并将它们存储在结构中:

char r, g, b;
ifs.read(&b, 1);
ifs.read(&g, 1);
ifs.read(&r, 1);

您可以查看示例1以查看图像行的存储方式。

首先,
BitMapInfo头的
biBitCount
字段是而不是每像素的字节数,它是位数

这是从原始数据中读取一个像素所需的位数。对于24位像素,只需按照Alessandro Pezzato或Ben的答案中的建议阅读即可。32位像素包含一个额外字节,该字节通常包含一个alpha通道(像素的透明度)。有多种不同的16位格式,8位格式通常是颜色表的索引。我不知道4位格式,但是1位是纯黑白的(0是黑色的,1是白色的)


对于8、16、24和32位格式,读取一到四个字节,并根据颜色格式进行转换。对于小于8(4和1)的值,一次读取一个字节,然后在循环中使用掩码获取位,并以内部格式存储。

首先,
BitMapInfo头的
biBitCount
字段是不是每个像素的字节数,它是位数

这是从原始数据中读取一个像素所需的位数。对于24位像素,只需按照Alessandro Pezzato或Ben的答案中的建议阅读即可。32位像素包含一个额外字节,该字节通常包含一个alpha通道(像素的透明度)。有多种不同的16位格式,8位格式通常是颜色表的索引。我不知道4位格式,但是1位是纯黑白的(0是黑色的,1是白色的)


对于8、16、24和32位格式,读取一到四个字节,并根据颜色格式进行转换。对于小于8(4和1)的值,一次读取一个字节,然后在循环中使用掩码获取位,并以内部格式存储。

为什么像素颜色为
int
?如果您不需要每像素超过8位,那么
无符号字符
(或
uint8\t
)就足够了。是的,我现在知道了,应该有无符号字符。但我还是有一个很大的问题,在某一时刻,我的意思是在我读取像素的时候,因为第一个参数需要读取函数*char,我不知道如何使它工作…:/为什么您的像素颜色类型为
int
?如果您不需要每像素超过8位,那么
无符号字符
(或
uint8\t
)就足够了。是的,我现在知道了,应该有无符号字符。但我还是有一个很大的问题,在某一时刻,我的意思是在我读取像素的时候,因为第一个参数需要读取函数*char,我不知道如何使它工作…:/Joahim,谢谢你的更正,但我已经知道biBitCount是像素的位数。这是一个打字错误…:P不管怎样。。。哇!谢谢你们的帮助。真正地现在我将测试这个,并告诉你们它是如何进行的:)但是伙计们。。。您是否查看了ifs.read()的工作原理。这个函数的第一个参数是char,这就是为什么我有一个大问题。So:int r,g,b;如果读取(&b,1);如果读取(&g,1);如果读取(&r,1);不起作用,同样uint8_t pixelTmp=新uint8_t[3];对于(inti=0;i!=imageSize;++i){ifs.read(pixelTmp,3);pixelTmp[0];/*是蓝色的0-255/pixelTmp[1];/是绿色的0-255/pixelTmp[2];/是红色的0-255*/},第一个参数是char*,一个指向缓冲区的指针。由于您只读取一个字符,因此只需选择指向变量的指针即可。我在考虑fgetc函数,这就是为什么我选择整数而不是字符。Joahim,谢谢你的更正,但我已经知道biBitCount是像素的位数。这是一个打字错误…:P不管怎样。。。哇!谢谢你们的帮助。真正地现在我将测试这个,并告诉你们它是如何进行的:)但是伙计们。。。您是否查看了ifs.read()的工作原理。这个函数的第一个参数是char,这就是为什么我有一个大问题。So:int r,g,b;如果读取(&b,1);如果读取(&g,1);如果读取(&r,1);不起作用,同样uint8_t pixelTmp=新uint8_t[3];对于(inti=0;i!=imageSize;++i){ifs.read(pixelTmp,3);pixelTmp[0];/*是蓝色的0-255/pixelTmp[1];/是绿色的0-255/pixelTmp[2];/是红色的0-255*/},第一个参数是char*,一个指向缓冲区的指针。由于您只读取一个字符,因此只需选择指向变量的指针即可。我考虑的是fgetc函数,这就是我选择int的原因