Получение значений RGB для каждого пикселя из растрового изображения 24bpp для преобразования в формат GBA в C - PullRequest
2 голосов
/ 07 октября 2009

Я хочу прочитать значения RGB для каждого пикселя из файла .bmp, чтобы я мог преобразовать bmp в формат, подходящий для GBA (GameBoy Advance).

Мне нужно получить только RGB для каждого пикселя, а затем записать эту информацию в файл.

Я пытаюсь использовать <windows.h> структуры:

typedef struct
{
    char signature[2];
    unsigned int fileSize;
    unsigned int reserved;
    unsigned int offset;
}BmpHeader;

typedef struct
{
    unsigned int headerSize;
    unsigned int width;
    unsigned int height;
    unsigned short planeCount;
    unsigned short bitDepth;
    unsigned int compression;
    unsigned int compressedImageSize;
    unsigned int horizontalResolution;
    unsigned int verticalResolution;
    unsigned int numColors;
    unsigned int importantColors;

}BmpImageInfo;

typedef struct
{
    unsigned char blue;
    unsigned char green;
    unsigned char red;
    unsigned char reserved;
}Rgb;

typedef struct
{
    BmpHeader header;
    BmpImageInfo info;
    Rgb colors[256];
    unsigned short image[1];
}BmpFile;

но мне нужна только структура RGB. Допустим, я прочитал «in.bmp»:

FILE *inFile, *outFile;
inFile = fopen("C://in.bmp", "rb");

Rgb Palette[256];
for(i=0;i<256;i++)
{
   fread(&Palette[i],sizeof(Rgb),1,inFile);
}

fclose(inFile);

Это правильно? Как мне записать в файл только информацию RGB?

Ответы [ 8 ]

4 голосов
/ 07 октября 2009

Я немного протестировал и немного расширил программу Патриса. Я не очень хороший программист на Си, так что вся заслуга ему, и мои части не такие элегантные, как у него - извините за это.

Предупреждение: впереди огромный исходный код.

#include <stdio.h>
#pragma pack(2)


typedef struct
{
    char signature[2];
    unsigned int fileSize;
    unsigned int reserved;
    unsigned int offset;
} BmpHeader;

typedef struct
{
    unsigned int headerSize;
    unsigned int width;
    unsigned int height;
    unsigned short planeCount;
    unsigned short bitDepth;
    unsigned int compression;
    unsigned int compressedImageSize;
    unsigned int horizontalResolution;
    unsigned int verticalResolution;
    unsigned int numColors;
    unsigned int importantColors;

} BmpImageInfo;

typedef struct
{
    unsigned char blue;
    unsigned char green;
    unsigned char red;
    //unsigned char reserved; Removed for convenience in fread; info.bitDepth/8 doesn't seem to work for some reason
} Rgb;


int main( int argc, char **argv ) {

    FILE *inFile;
    BmpHeader header;
    BmpImageInfo info;
    Rgb *palette;
    int i = 0;

    printf( "Opening file %s for reading.\n", argv[1] );

    inFile = fopen( argv[1], "rb" );
    if( !inFile ) {
        printf( "Error opening file %s.\n", argv[1] );
        return -1;
    }

    if( fread(&header, 1, sizeof(BmpHeader), inFile) != sizeof(BmpHeader) ) {
        printf( "Error reading bmp header.\n" );
        return -1;
    }

    if( fread(&info, 1, sizeof(BmpImageInfo), inFile) != sizeof(BmpImageInfo) ) {
        printf( "Error reading image info.\n" );
        return -1;
    }

    if( info.numColors > 0 ) {
        printf( "Reading palette.\n" );
        palette = (Rgb*)malloc(sizeof(Rgb) * info.numColors);
        if( fread(palette, sizeof(Rgb), info.numColors, inFile) != (info.numColors * sizeof(Rgb)) ) {
            printf( "Error reading palette.\n" );
            return -1; // error
        }
    }

    printf( "Opening file %s for writing.\n", argv[2] );
    FILE *outFile = fopen( argv[2], "wb" );
    if( !outFile ) {
        printf( "Error opening outputfile.\n" );
        return -1;
    }
    Rgb *pixel = (Rgb*) malloc( sizeof(Rgb) );
    int read, j;
    for( j=0; j<info.height; j++ ) {
        printf( "------ Row %d\n", j+1 );
        read = 0;
        for( i=0; i<info.width; i++ ) {
            if( fread(pixel, 1, sizeof(Rgb), inFile) != sizeof(Rgb) ) {
                printf( "Error reading pixel!\n" );
                return -1;
            }
            read += sizeof(Rgb);
            printf( "Pixel %d: %3d %3d %3d\n", i+1, pixel->red, pixel->green, pixel->blue );
        }
        if( read % 4 != 0 ) {
            read = 4 - (read%4);
            printf( "Padding: %d bytes\n", read );
            fread( pixel, read, 1, inFile );
        }
    }

    printf( "Done.\n" );
    fclose(inFile);
    fclose(outFile);

    printf( "\nBMP-Info:\n" );
    printf( "Width x Height: %i x %i\n", info.width, info.height );
    printf( "Depth: %i\n", (int)info.bitDepth );

    return 0;

}

Эта программа считывает информацию о пикселях, хранящуюся в файле. Он учитывает отступы, но работает только с bmp с глубиной цвета 24 бита на пиксель (если вам нужны другие глубины, вам придется настроить структуру Rgb). Надеюсь, это поможет вам, но, как я уже сказал, это всего лишь расширение кода Патриса.

Вот пример вывода из моего тестового файла:

$ ./a.out test.bmp out.txt
Opening file test.bmp for reading.
Opening file out.txt for writing.
------ Row 1
Pixel 1:   0   0   0
Pixel 2:   0   0   0
Pixel 3:   0   0   0
Pixel 4:   0   0   0
Pixel 5:   0   0   0
Padding: 1 bytes
------ Row 2
Pixel 1:   0   0   0
Pixel 2: 232  33  33
Pixel 3:   0   0   0
Pixel 4: 232  33  33
Pixel 5:   0   0   0
Padding: 1 bytes
------ Row 3
Pixel 1:   0   0   0
Pixel 2:   0   0   0
Pixel 3: 232  33  33
Pixel 4:   0   0   0
Pixel 5:   0   0   0
Padding: 1 bytes
------ Row 4
Pixel 1:   0   0   0
Pixel 2: 232  33  33
Pixel 3:   0   0   0
Pixel 4: 232  33  33
Pixel 5:   0   0   0
Padding: 1 bytes
------ Row 5
Pixel 1:   0   0   0
Pixel 2:   0   0   0
Pixel 3:   0   0   0
Pixel 4:   0   0   0
Pixel 5:   0   0   0
Padding: 1 bytes
Done.

BMP-Info:
Width x Height: 5 x 5
Depth: 24

Редактировать: Да, мое изображение отображает красный крест. Обратите внимание, что изображение хранится в обратном порядке, поэтому строка 1 файла фактически является строкой 5 изображения. Д'Ох забыл написать что-нибудь, чтобы файл открывал код, но это оставлено вам на усмотрение;).

4 голосов
/ 07 октября 2009

Если вы работаете в Windows, вы можете использовать функцию LoadBitmap из win32

затем, используя дескриптор, преобразуйте его в растровое изображение DIB и получите таким образом пиксели

3 голосов
/ 07 октября 2009

Сначала необходимо получить количество цветов, доступных во встроенной палитре. Это доступно в заголовке DIB.

Затем вы можете прочитать все цветовые компоненты, которые содержат палитру.

Вы можете увидеть всю информацию заголовка, например смещение, чтобы узнать, где искать: http://en.wikipedia.org/wiki/BMP_file_format.

Это должно работать: (Редактировать: добавить код для записи в файл)

FILE *inFile, *outFile;
BMPHeader header;
BMPImageInfo info;
RGB *palette, *p;
int i = 0;

inFile = fopen("C://in.bmp", "rb");
if( !inFile )
   return;

if( fread(&header, sizeof(BMPHeader), 1, inFile) != 1 )
   return; // Manage error and close file

if( fread&info, sizeof(BMPImageInfo), 1, inFile) != 1 )
   return; // Manage error and close file

if( info.numColors > 0 )
{
   palette = (RGB*)malloc(sizeof(RGB) * info.numColors);
   if( fread(palette, sizeof(RGB), info.numColors, inFile) != info.numColors )
      return; // manage error and close file
}

fclose(inFile)

// Binary method => if read later by another computer
outFile = fopen("path", "wb");
if( !outFile )
   return;

if( fwrite(&info.numColors, sizeof(unsigned int), 1, outFile) != 1 )
   return; // Manage Error and close file

if( fwrite(&palette, sizeof(RGB), info.numColors, outFile) != info.numColors )
   return; // Manage error and close file

fclose(outFile);

// Text method => if read later by human
outFile = fopen("path", "w");
if( !outFile )
   return;

for( i=0; i<info.numColors; ++i )
{
   p = &palette[i];
   if( fprintf(outFile, "R:%d, G:%d, B:%d\n", p->red, p->green, p->blue) < 0 )
      return; // Manage error and close file
}

fclose(outFile);
2 голосов
/ 07 октября 2009

Если вы уверены, что это несжатый битовый массив 24bpp и его ширина делится на 4, это относительно просто:

  1. Считайте BmpHeader в начале файла.
  2. Не ищите, прочитайте BmpImageInfo.
  3. Поиск BmpHeader offset байтов от начала файла . Обратите внимание, что в 24-битных растровых изображениях нет палитры (по крайней мере, той, которая нам не нужна)!
  4. Считать тройки BGR (в таком порядке, и здесь нет неиспользованного члена reserved). Будут (BmpImageInfo участники) width * abs(height) тройки. Насколько я помню, если height является положительным (стандартный случай), первая прочитанная вами строка цвета будет нижней строкой изображения, идущей оттуда вверх. Если height отрицательно, первая цветная строка в файле - это top изображения, идущего вниз оттуда.

Если вы не можете сделать эти гарантии, тогда все становится намного сложнее.

Отказ от ответственности: я даром перевожу здесь свой рог В) путь: glbmp libbmpread . Его источник может пролить свет на вашу проблему - он обрабатывает неосмысленные (без RLE) растровые изображения любой битовой глубины и должен нормально работать на GBA.

1 голос
/ 07 октября 2009

См. Страницу википедии в формате файла .bmp, которая предоставляет много информации о структуре файла и должна помочь вам разобрать его.

http://en.wikipedia.org/wiki/BMP_file_format

В вашем коде вы сначала должны прочитать начальный адрес данных (указанный в заголовке файла) и высоту изображения. Тогда стремитесь к этой позиции. После этого вы читаете по одной строке пиксель за пикселем (заголовок указывает, сколько бит на пиксель) и должны позаботиться о 32-битном заполнении в конце. Обратите внимание, что в 24-битном изображении (RGB) информация хранится в порядке BGR. Также, если значение высоты не является отрицательным, изображение сохраняется вверх ногами.

0 голосов
/ 08 октября 2009

Возможно, вам будет полезно взглянуть на код C, который я написал много лет назад для чтения и записи файлов BMP, расположенный по адресу:

http://david.tribble.com/src/bmp/bmp.html

Я считаю, что он обрабатывает биты разного размера (1/2/4/8/24), а также RLE-сжатие.

0 голосов
/ 07 октября 2009

Если файл BMP имеет палитру, то код ниже должен работать:

  FILE *inFile, *outFile;
  inFile = fopen("C:/in.bmp", "rb");
  Rgb Palette[256];
  if ( inFile ) {
    // Bypass headers
    fseek(inFile, sizeof(BmpHeader) + sizeof(BmpImageInfo), SEEK_SET);
    // Load the whole palette
    fread(Palette, sizeof(Palette), 1, inFile);
    fclose(inFile);
  }
0 голосов
/ 07 октября 2009

Я не знаком с форматом файла BMP, но не нужно ли вам сначала прочитать информацию в заголовке? Что-то вроде:

BmpHeader header;
fread(&header,sizeof(BmpHeader),1,inFile);

и прочитайте подробную информацию об изображении, которая вам понадобится:

BmpImageInfo info;
fread(&info,sizeof(BmpImageInfo),1,inFile);

и прочитайте информацию в палитре.

как только вы это узнаете, вы узнаете размер файла и смещение данных. Вы можете заранее выделить достаточно места и сразу прочитать все, что может быть самым простым. В качестве альтернативы вы можете читать по частям и разбирать по ходу (уменьшает вероятность нехватки памяти, но разбирать более сложно).

Вы также узнаете из раздела информации, включено ли сжатие, размеры изображения и т. Д.

Если вы читаете все сразу, перейдите к смещению данных и сделайте что-то вроде:

Rgb* rgb = offset;
blueVal = rgb->blue;
greenVal = rgb->green;
redVal = rgb->red;
rgb += sizeof( Rgb );

и т. Д. Очевидно, что код не проверяет наличие ошибок, конца буфера и т. Д., Поэтому вам нужно это сделать. Возможно, вам также придется прочитать информацию о палитре, чтобы понять данные изображения.

Или, как кто-то еще сказал, посмотрите спецификацию формата в Википедии

...