Как читать пиксель за пикселем в BMP - PullRequest
2 голосов
/ 29 декабря 2011

У меня проблема! Я хотел бы получить информацию о RGB каждого пикселя в 24-битном растровом изображении. До сих пор я написал код, который получает информацию о растровом изображении, но у меня есть проблема с получением RGB-информации о каждом пикселе. Я хотел бы сохранить эту информацию в пикселях таблиц структур Pixel. Не могли бы вы помочь мне с этим?

Я поставил свой код ниже:

     #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;

}

Это работает, но как мне изменить это для некоторой целочисленной переменной? Например:

pixs[i][j]=(unsigned int)r;

не работает. После этой команды в пикселях [i] [j] есть мусор ...: /

Может быть, какой-нибудь совет?

Ответы [ 3 ]

0 голосов
/ 29 декабря 2011

Как вы можете видеть здесь , 1 пиксель использует 3 байта. Это означает, что первый байт синий, второй зеленый и третий красный. Что вы должны сделать сейчас, это перебрать оставшуюся часть растрового файла, прочитав 3 отдельных байта и сохранив их в своей структуре:

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

Вы можете проверить пример 1, чтобы увидеть, как хранятся строки изображения.

0 голосов
/ 29 декабря 2011

Прежде всего, поле biBitCount поля BITMAPINFOHEADER равно , а не число байтов на пиксель, это число битов .

Это количество бит, которое необходимо прочитать из необработанных данных, чтобы получить один пиксель.Для 24-битных пикселей просто прочитайте, как предложено в ответах Алессандро Пеццато или Бена.32-битные пиксели содержат дополнительный байт, который обычно содержит альфа-канал (насколько прозрачен пиксель.) Существует несколько различных 16-битных форматов, а 8-битный формат обычно является индексом в таблице цветов.Я не знаю о 4-битных форматах, но 1-битный - чисто черно-белый (0 - черный, а 1 - белый.)

Для 8, 16, 24 и 32-битных форматов:читать от одного до четырех байтов и конвертировать в соответствии с форматом цвета.Для значений меньше 8 (4 и 1) считывайте по одному байту за раз, а затем используйте маскирование в цикле для получения битов и сохраняйте их в своем внутреннем формате.

0 голосов
/ 29 декабря 2011

Если у вас есть смещение и размер изображения и вы уверены, что изображение имеет размер 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] своему синему пикселю и т. Д. ...

...