Проблемы с переносом при импорте BMP в C - PullRequest
0 голосов
/ 12 октября 2011

Сейчас я работаю над программой для моего курса по обработке визуальной информации.Мы получили скелетные шаблоны для всех домашних заданий, поскольку в центре внимания класса не изучение MFC.Я программирую на Mac и не имею доступа к библиотеке Windows, что упрощает импорт BMP.Поэтому я использовал (и немного изменил) код, найденный на этом сайте: paulbourke.net / dataformats / bmp / ​​

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

Когда я импортирую BMP в массивтипа GLubyte, и изображение имеет biBitCount = 24, использование GLDrawPixels прекрасно работает:

http://i.imgur.com/41TVo.png

Однако, когда я импортирую BMP с biBitCount = 8 и отображаю его с помощью GLDrawPixels, я получаюследующее (обратите внимание на ошибку обтекания, выделенную красным прямоугольником):

http://i.imgur.com/xws5j.png

Мне пришлось реализовать алгоритм автоматического определения порога для моего последнего назначения, чтобы облегчить сегментацию изображения наинтерпретируемые регионы.Я думаю, что ошибка для этой обертки связана с импортом BMP, а не с вызова GLDrawPixels.Это связано с тем, что созданный мною алгоритм регионализации определил больше регионов, чем следовало бы.Что, по-видимому, подразумевает, что та часть, которая обернута вокруг, действительно не пересекается в представлении массива BMP.

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

Вот код, который отображает BMP после его импорта:

void drawBMP(BITMAPINFO *bitmapInfo, GLubyte *bitmapIn, GLfloat xOffset, GLfloat yOffset) {
if (bitmapInfo) {
    glRasterPos2f(xOffset, yOffset);

    if (bitmapInfo->bmiHeader.biBitCount == 24) {
        glDrawPixels(bitmapInfo->bmiHeader.biWidth,
                     bitmapInfo->bmiHeader.biHeight,
                     GL_BGR, GL_UNSIGNED_BYTE, bitmapIn);
    } else {
        glDrawPixels(bitmapInfo->bmiHeader.biWidth,
                     bitmapInfo->bmiHeader.biHeight,
                     GL_LUMINANCE, GL_UNSIGNED_BYTE, bitmapIn);
    }
}

glFinish();
}

Возможно, проблема вызвана настройкой GL_LUMINANCE?

Вот функция, которая выполняет фактический импортиз BMP:

GLubyte *                          /* O - Bitmap data */
LoadDIBitmap(const char *filename, /* I - File to load */
         BITMAPINFO **info)    /* O - Bitmap information */
{
FILE             *fp;          /* Open file pointer */
GLubyte          *bits;        /* Bitmap pixel bits */
GLubyte          *ptr;         /* Pointer into bitmap */
GLubyte          temp;         /* Temporary variable to swap red and blue */
int              x, y;         /* X and Y position in image */
int              length;       /* Line length */
int              bitsize;      /* Size of bitmap */
int              infosize;     /* Size of header information */
BITMAPFILEHEADER header;       /* File header */


/* Try opening the file; use "rb" mode to read this *binary* file. */
if ((fp = fopen(filename, "rb")) == NULL)
    return (NULL);

/* Read the file header and any following bitmap information... */
header.bfType      = read_word(fp);
header.bfSize      = read_dword(fp);
header.bfReserved1 = read_word(fp);
header.bfReserved2 = read_word(fp);
header.bfOffBits   = read_dword(fp);

if (header.bfType != BF_TYPE) /* Check for BM reversed... */
    {
    /* Not a bitmap file - return NULL... */
    fclose(fp);
    return (NULL);
    }

infosize = header.bfOffBits - 18;
if ((*info = (BITMAPINFO *)malloc(sizeof(BITMAPINFO))) == NULL)
    {
    /* Couldn't allocate memory for bitmap info - return NULL... */
    fclose(fp);
    return (NULL);
    }

(*info)->bmiHeader.biSize          = read_dword(fp);
(*info)->bmiHeader.biWidth         = read_long(fp);
(*info)->bmiHeader.biHeight        = read_long(fp);
(*info)->bmiHeader.biPlanes        = read_word(fp);
(*info)->bmiHeader.biBitCount      = read_word(fp);
(*info)->bmiHeader.biCompression   = read_dword(fp);
(*info)->bmiHeader.biSizeImage     = read_dword(fp);
(*info)->bmiHeader.biXPelsPerMeter = read_long(fp);
(*info)->bmiHeader.biYPelsPerMeter = read_long(fp);
(*info)->bmiHeader.biClrUsed       = read_dword(fp);
(*info)->bmiHeader.biClrImportant  = read_dword(fp);

if (infosize > 40)
if (fread((*info)->bmiColors, infosize - 40, 1, fp) < 1)
        {
        /* Couldn't read the bitmap header - return NULL... */
        free(*info);
        fclose(fp);
        return (NULL);
        }

/* Now that we have all the header info read in, allocate memory for *
 * the bitmap and read *it* in...                                    */
if ((bitsize = (*info)->bmiHeader.biSizeImage) == 0)
    bitsize = ((*info)->bmiHeader.biWidth *
               (*info)->bmiHeader.biBitCount+7) / 8 *
           abs((*info)->bmiHeader.biHeight);

if ((bits = malloc(bitsize)) == NULL)
    {
    /* Couldn't allocate memory - return NULL! */
    free(*info);
    fclose(fp);
    return (NULL);
    }

if (fread(bits, 1, bitsize, fp) < bitsize)
    {
    /* Couldn't read bitmap - free memory and return NULL! */
    free(*info);
    free(bits);
    fclose(fp);
    return (NULL);
    }

//This needs to be done when the height is negative
if ((*info)->bmiHeader.biHeight < 0) {
    (*info)->bmiHeader.biHeight *= -1;

    int bitsPerPixel = (*info)->bmiHeader.biBitCount;
    int bytesPerPixel;
    if (bitsPerPixel >= 8) {
        bytesPerPixel = bitsPerPixel/8;
    } else {
        exit(1);
    }       

    int i;  //Row
    int j;  //Column
    for (i = 0; i < floor((*info)->bmiHeader.biHeight/2); i++) {
        int inlineRowValue = i * (*info)->bmiHeader.biWidth * bytesPerPixel;
        int inlineInvRowValue = ((*info)->bmiHeader.biHeight - i) * (*info)->bmiHeader.biWidth * bytesPerPixel;

        for (j = 0; j < (*info)->bmiHeader.biWidth; j++) {
            int inlineColumnValue = j * bytesPerPixel;
            int currentPos = inlineRowValue + inlineColumnValue;
            int invCurrentPos = inlineInvRowValue + inlineColumnValue;

            int k;
            GLubyte *temp = malloc(sizeof(GLubyte)*bytesPerPixel);
            for (k = 0; k < bytesPerPixel; k++) {
                temp[k] = bits[currentPos+k];                   
            }
            for (k = 0; k < bytesPerPixel; k++) {
                bits[currentPos+k] = bits[invCurrentPos+k];
                bits[invCurrentPos+k] = temp[k];    
            }               

            free(temp);
        }
    }
}

/* OK, everything went fine - return the allocated bitmap... */
fclose(fp);
return (bits);
}

Моя интуиция подсказывает мне, что указатель файла не увеличивается должным образом, поскольку вещи считываются из файла BMP.

Если вы, ребята, знаете, каков источник этой ошибки, пожалуйста, поделитесь.Я буду невероятно благодарен.Это сводит меня с ума.

1 Ответ

3 голосов
/ 12 октября 2011

Я думаю, что вы вычитаете неправильную сумму здесь:

infosize = header.bfOffBits - 18;

Это, кажется, учитывает размер информации заголовка, но заголовок составляет 14 байтов (3 слова и 2 слова), а не18 байт.

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

fseek(fp, header.bfOffBits, SEEK_SET);

перед чтением данных изображения?

...