преобразование 24-битного цветного изображения bmp в 8-битное изображение bmp в оттенках серого в c

Я пытаюсь преобразовать цветное изображение BMP 24bpp в изображение BMP в градациях серого 8bpp. Я что-то сделал, но я не получаю 100% правильный вывод.

Я преобразовал 24bpp в 8bpp. но в результате таблица цветов изображения также рассматривается как данные пикселей. Я попытался установить байт смещения в заголовке, но проблема все еще сохраняется.

#include <stdio.h>

int main()
{

    FILE* fIn = fopen("lena_colored_256.bmp","rb");         
    FILE* fOut = fopen("lena_gray.bmp", "w+");              
    int i, j, y;
    unsigned char byte[54];
    unsigned char colorTable[1024];
    if (fIn == NULL)// check if the input file has not been opened
    {
        printf("File does not exist.\n");
    }

    for (i = 0; i < 54; i++)//read the 54 byte header from fIn
    {
        byte[i] = getc(fIn);

    }
    byte[28] = (unsigned char)8; // write code to modify bitDepth to 8

    byte[11] = (unsigned char)04;
    //write code to add colorTable

    for (i = 0; i < 256; i++)
    {
            colorTable[i * 4 + 0] = i;
            colorTable[i * 4 + 1] = i;
            colorTable[i * 4 + 2] = i;
            colorTable[i * 4 + 3] = i;
    }


    for (i = 0; i < 54; i++)
    {
        putc(byte[i], fOut);
    }
    for (i = 0; i < 1024; i++)
    {
        putc(colorTable[i], fOut);

    }
        // extract image height, width and bitDepth from imageHeader 
    int *height = (int)& byte[18];
    int *width = (int)& byte[22];
    int *bitDepth = (int)& byte[28];

    printf("bitDepth : %d\n", *bitDepth);
    printf("width: %d\n", *width);
    printf("height: %d\n", *height);
    int size = (*height) * (*width)*3; //calculate image size

    unsigned char* buffer;
    buffer = (unsigned char*)malloc(sizeof(int) * size);

    for (i = 0; i < size; i=i+3)    //RGB to gray
    {

        buffer[i+2] = getc(fIn);//blue
        buffer[i+1] = getc(fIn);//green
        buffer[i+0] = getc(fIn);//red

        y = (buffer[i+0] * 0.33) + (buffer[i+1] * 0.33) + (buffer[i+2] * 0.33);

        putc(y, fOut);
    }


    fclose(fOut);
    fclose(fIn);

    return 0;
}

Данные таблицы цветов также рассматриваются как пиксельные данные изображения. я проверил ввод данных таблицы цветов в файл BMP. Я распечатал местоположение указателя файла, после ввода 94-го байта он увеличивается на 2 байта вместо 1 байта, всего это происходит 4 раза, а другой указатель файла 1020 раз увеличивается на 1 байт. Любое объяснение по этому поводу?


person prateek k    schedule 25.07.2019    source источник
comment
Возможный дубликат Преобразование цветного bmp в оттенки серого bmp? - хотя и не точно. Использование unsigned char здесь правильно.   -  person David C. Rankin    schedule 25.07.2019
comment
Без таблицы цветов изображение не формируется, т.е. возникает какая-то ошибка при открытии выходного изображения   -  person prateek k    schedule 25.07.2019
comment
24-битному изображению BMP не нужна таблица цветов, но 8-битному изображению BMP нужна таблица цветов. abhijitnathwani.github.io/blog/ 2017/12/19/   -  person prateek k    schedule 25.07.2019
comment
Вам нужна только таблица цветов с изображением 8bpp, если оно не в оттенках серого. Тогда вам нужна палитра.   -  person Weather Vane    schedule 25.07.2019
comment
@WeatherVane Я был неправ, палитра обязательна для изображений, где bpp ‹= 8 Таким образом, есть два варианта изображения в оттенках серого: 8 бит на пиксель с серой палитрой или более 8 бит на пиксель (например, 24 бит на пиксель), где каждый пиксель серый.   -  person user3386109    schedule 25.07.2019
comment
@prateekk В заголовках растровых изображений нужно изменить четыре поля: bfSize, bfOffset , biSizeImage и biBitCount. Кроме того, необходимо правильно обрабатывать байты заполнения (каждая строка данных изображения должна содержать число, кратное четырем байтам). Обратите внимание, что байты заполнения включены в bfSize и biSizeImage. И размер палитры включен в bfSize и bfOffset.   -  person user3386109    schedule 25.07.2019
comment
@user3386109 user3386109 хм, я уверен, что использовал его с прямым сопоставлением. В конце концов, существует 256 оттенков серого, поэтому нет смысла их сопоставлять, разве что для гамма-коррекции. Возможно, зрители изображений терпимы.   -  person Weather Vane    schedule 25.07.2019
comment
@WeatherVane Да, я, кажется, припоминаю, что делал это в какой-то момент в прошлом. Возможно, я неправильно помню, и это был другой формат файла. В любом случае средства просмотра, которые я пробовал сегодня, не будут принимать изображение 8bpp, если у него нет палитры.   -  person user3386109    schedule 25.07.2019
comment
@user3386109 user3386109 я проверил ввод данных таблицы цветов в файл BMP. Я распечатал местоположение указателя файла, после ввода 94-го байта он увеличивается на 2 байта вместо 1 байта, всего это происходит 4 раза, а другой указатель файла 1020 раз увеличивается на 1 байт. Любое объяснение по этому поводу?   -  person prateek k    schedule 26.07.2019
comment
В заголовке указано, что ввод представляет собой 24-битное растровое изображение, но в коде указано "lena_colored_256.bmp", что предполагает, что ввод является 8-битным. Покажи распечатку для printf("bitDepth : %d\n", *bitDepth);   -  person Barmak Shemirani    schedule 27.07.2019
comment
@BarmakShemirani, это изображение 256x256. BitDepth изначально 24, я меняю его на 8, имя изображения не должно иметь значения для моей проблемы.   -  person prateek k    schedule 27.07.2019
comment
Приведение указателей к int очень неправильно   -  person Antti Haapala    schedule 05.08.2019


Ответы (1)


Преобразование 24-битного в 8-битное растровое изображение не так просто, как изменение битового счета в заголовочном файле. 24-битное растровое изображение не имеет таблицы цветов. Вы должны построить таблицу цветов для 8-битного. К счастью, это относительно просто для изображений в оттенках серого.

Необходимо изменить несколько значений в заголовочном файле растрового изображения.

Затем измените 24-битную шкалу на серую и измените на 8-битное растровое изображение. Дополнительную информацию см. в формате файла растрового изображения. Также прочитайте о «заполнении», где ширина растрового изображения в байтах всегда должна быть кратна 4.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#pragma pack(push, 2)
typedef struct {
    int16_t bfType;
    int32_t bfSize;
    int16_t bfReserved1;
    int16_t bfReserved2;
    int32_t bfOffBits;
} BITMAPFILEHEADER;

typedef struct {
    int32_t biSize;
    int32_t biWidth;
    int32_t biHeight;
    int16_t biPlanes;
    int16_t biBitCount;
    int32_t biCompression;
    int32_t biSizeImage;
    int32_t biXPelsPerMeter;
    int32_t biYPelsPerMeter;
    int32_t biClrUsed;
    int32_t biClrImportant;
} BITMAPINFOHEADER;
#pragma pack(pop)

int main()
{
    FILE* fin = fopen("fin.bmp", "rb");
    FILE* fout = fopen("fout.bmp", "wb");
    if(!fin) { printf("fin error\n"); goto error; }
    if(!fout) { printf("fout error\n"); goto error; }

    BITMAPFILEHEADER bf;
    BITMAPINFOHEADER bi;
    fread(&bf, sizeof bf, 1, fin);
    fread(&bi, sizeof bi, 1, fin);

    if(sizeof bf != 14) { printf("Wrong pragma pack\n"); goto error; }
    if(sizeof bi != 40) { printf("Wrong pragma pack\n"); goto error; }
    if(bf.bfType != 0x4D42) { printf("not bmp, or not LE system\n"); goto error; }
    if(bi.biSize != 40) { printf("Can't handle this bitmap format\n"); goto error; }
    if(bi.biBitCount != 24) { printf("not 24-bit\n"); goto error; }

    int height = bi.biHeight;
    if(height < 0) height = -height; 

    //width in bytes:
    int src_wb = ((bi.biWidth * 24 + 31) / 32) * 4;
    int dst_wb = ((bi.biWidth * 8 + 31) / 32) * 4;
    int src_size = src_wb * height;
    int dst_size = dst_wb * height;

    //allocate for source and destination
    uint8_t *src = malloc(src_size);
    uint8_t *dst = malloc(dst_size);

    //read pixels
    fread(src, 1, src_size, fin);

    //make gray scale color-table
    uint8_t clr[1024] = { 0 };
    for(int i = 0; i < 256; i++)
        clr[i * 4 + 0] = clr[i * 4 + 1] = clr[i * 4 + 2] = (uint8_t)i;

    for(int y = height - 1; y >= 0; y--)
    {
        for(int x = 0; x < bi.biWidth; x++)
        {
            uint8_t blu = src[y * src_wb + x * 3 + 0];
            uint8_t grn = src[y * src_wb + x * 3 + 1];
            uint8_t red = src[y * src_wb + x * 3 + 2];
            uint8_t gry = (uint8_t)(.33 * red + .34 * grn + .33 * blu);
            dst[y * dst_wb + x] = gry; //this will match the index in color-table
        }
    }

    //modify bitmap headers
    bf.bfSize = 54 + 1024 + dst_size;
    bi.biBitCount = 8;
    bi.biSizeImage = dst_size;

    fwrite(&bf, sizeof bf, 1, fout);
    fwrite(&bi, sizeof bi, 1, fout);
    fwrite(clr, 1, 1024, fout);
    fwrite(dst, 1, dst_size, fout);
    free(src);
    free(dst);
error:
    fclose(fout);
    fclose(fin);
    return 0;
}
person Barmak Shemirani    schedule 27.07.2019