Проблема извлечения пиксельных данных из растрового изображения

Я использую собственный С++ без создания библиотеки обработки изображений с нуля, в настоящее время для растровых изображений.

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

fread(pixelDataBuffer, sizeof(unsigned char), (height * width), streamIn);

Где высота и ширина — размеры растрового изображения в пикселях. Я думал, что это будет работать и имеет смысл для изображения с 8 битами на пиксель, но это все еще не работает (функция возвращает 0). Это происходит даже несмотря на то, что высота и ширина имеют значения 256 каждое, а pixelDataBuffer инициализируется, как показано ниже:

unsigned char pixelDataBuffer[height * width]; 
// also tried:
unsigned char pixelDataBuffer[65536]; // which is 256*256

Спасибо!

Добавление дополнительного кода для ясности:

bool isTrial = true;
FILE *streamIn;
FILE *outputFile;

int main(int argc, const char * argv[]) {

    if (isTrial) {
        streamIn = fopen("Images/cameraman.bmp", "rb");
        outputFile = fopen("Images/cameraman_copy.bmp", "wb");
    } else {
        streamIn = fopen("Images/flag.bmp", "rb");
        outputFile = fopen("Images/flag_copy.bmp", "wb");
    }

    unsigned char header[54];
    unsigned char colourTable[1024];

    if (streamIn == nullptr) {
        printf("null pointer");
    } else {

        for (int i = 0; i < 54; i++) {
            header[i] = getc(streamIn);
        }

        unsigned int width = *(int*)&header[18];
        cout << "width: " << width << "\n"; // = 256

        unsigned int height = *(int *)&header[22];
        cout << "height: " << height << "\n"; // = 256

        unsigned short bitDepth = *(short *)&header[28];
        cout << "bitDepth: " << bitDepth << "\n"; // = 8

        unsigned int fileSize = *(int *)&header[2];
        cout << "fileSize: " << fileSize << endl; // 66614

        if (1 < bitDepth && bitDepth <= 8) {
            short count = fread(colourTable, sizeof(unsigned char), 1024, streamIn); 
            if (count == 1024) {
                printf("colourTable read\n"); // colourTable gets read
            } else {
                printf("colourTable NOT read properly");
            }
        } else {
            printf("bitsPerPixel / bitDepth is more than 8");
        }


        { // getting pixelData, at this point I assumed that the stream's position starts where pixel data starts (i.e. after Headers & ColourTable)

            unsigned int pixelDataSize = height * width * (bitDepth/8); // = 65536
            cout << "pixelDataSize: " << pixelDataSize << endl;

            unsigned char pixelDataBuffer[pixelDataSize]; // also tried initializing like unsigned char pixelDataBuffer[height*width]

            short counter = fread(pixelDataBuffer, sizeof(unsigned char), pixelDataSize, streamIn);
            cout << "counter: " << counter << endl; // = 0 THIS IS THE ISSUE. Documentation says "If either size or count is zero, the function returns zero and both the stream state and the content pointed by ptr remain unchanged." But I think I have size and count >0 correctly?

        }


        { // writing our header onto the outputFile
            short count = fwrite(header, sizeof(unsigned char), 54, outputFile);
            if (count == 54) {
                printf("header written\n"); // Header gets written
            } else {
                printf("header not written");
            }
        }
    }
    return 0;
}

вам следует прочитать документацию, относящуюся к каждому формату изображения, однако я предполагаю, что вы должны использовать 16-битный тип, такой как uint16_t, также вам, вероятно, следует использовать uint8_t вместо unsigned char, чтобы убедиться, что у вас есть правильный размер

xception 22.05.2019 15:05

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

xception 22.05.2019 15:10

однозначно за опыт :)

John Paoletto 22.05.2019 15:11

попробуйте прочитать спецификации, чем dragonwins.com/domains/GetTechEd/bmp/bmpfileformat.htm, имейте в виду, что вы можете встретить 1-битные растровые изображения, в которых 1 байт представляет 8 пикселей.

xception 22.05.2019 15:13

Да, я полагаю, мне просто нужно умножить количество пикселей на количество байтов на пиксель в случае моей функции. Но моя первоначальная проблема с fread (как указано выше), возвращающим 0, остается, даже несмотря на то, что высота и ширина имеют значения 256 каждое.

John Paoletto 22.05.2019 15:17

ты стрим открыл? нужно больше кода для выводов. Всегда проверяйте, удалось ли открытие, поиск и т. д.

xception 22.05.2019 15:32

ОК, я добавил окружающий код и комментарии, чтобы показать результаты выполнения!!

John Paoletto 22.05.2019 15:38

Вы понимаете, что файлы BMP используют сжатие, верно?

Cris Luengo 22.05.2019 15:40

@Cris, да, но этого файла нет. Это мой стартовый файл :) Простое растровое изображение 8 бит на пиксель, без сжатия

John Paoletto 22.05.2019 15:41

Кроме того, bitDepth/8 равно 0, если bitDepth<8. И unsigned char pixelDataBuffer[pixelDataSize]; недопустим в C++, это должна быть константа времени компиляции. Используйте std::vector для ваших буферов.

Cris Luengo 22.05.2019 15:54

@Крис хорошо, так и сделаю

John Paoletto 22.05.2019 15:59
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
11
107
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваша проблема заключается в объявлении результата fread коротким.

Старайтесь всегда использовать auto как можно чаще. С использованием:

auto counter = fread(pixelDataBuffer, sizeof(unsigned char), pixelDataSize, streamIn);

заставляет это работать. Проблема в том, что 65536 не может быть представлена ​​вкратце, на самом деле он переполняет его ровно настолько, чтобы казалось, что вместо этого результат был 0.

Если вы используете более старую версию C++ (до C++11) и не можете использовать auto вместо этого используйте size_t (который является фактическим возвращаемым типом fread).

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

Другие вопросы по теме