Сохранить изображения с плавающей запятой * в C++

Я хотел понять, как я могу сохранить изображение типа float:

float * image;

Распределено таким образом:

int size = width * height;
image = (float *)malloc(size * sizeof(float));

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

CImg<float> image("image.jpg");
int width = image.width(); 
int height = image.height();
int size = width*height
float * image = image.data();

Как сохранить эту картинку в float из .jpg или .bmp для чтения. Я думал открыть буфер записи, но ничего не сохраняется, и я не могу читать из файла!


person user2485282    schedule 04.08.2013    source источник
comment
Откуда эти изображения? Что такое диапазон с плавающей запятой? Я почти уверен, что вам нужно сначала нормализовать формат до целочисленного значения.   -  person Mats Petersson    schedule 04.08.2013


Ответы (5)


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

image=(float *)malloc(size* sizeof(float));

а потом ты делаешь

float * image =image.data();

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

теперь вы должны прочитать CImg здесь и увидеть, что Data() возвращает указатель на первый пиксель Изображение.

теперь, когда мы все это установили, давайте перейдем к решению: если вы хотите сохранить массив с плавающей запятой в файл, используйте этот пример

#include <fstream.h>

void saveArray(float* array, int length);

int main()
{
    float image[] = { 15.25, 15.2516, 84.168, 84356};
    saveArray(floatArray, sizeof(image)/ sizeof(image[0]));

    return 0;
}

void saveArray(float* array, int length)
{
    ofstream output("output.txt");

    for(int i=0;i<length;i++)
    {
        output<<array[i]<<endl;
    }
}
person No Idea For Name    schedule 04.08.2013
comment
Здравствуйте, спасибо за ответ. Всем понятно кроме одного: почему output.txt это txt а не bmp или jpg? - person user2485282; 04.08.2013
comment
потому что я до сих пор не знаю вашей цели... вы начинаете с .jpg, поэтому я не знаю, почему вы откроете его, а затем снова сохраните... если вы хотите просто скопировать его, есть более простые способы - person No Idea For Name; 04.08.2013
comment
хорошо, я скажу вам, я хочу открыть изображение, передать его в float, применить алгоритм, сделанный мной, а затем сохранить этот float в моей папке назначения в читаемом формате ;-) - person user2485282; 04.08.2013
comment
я не уверен в формате файлов bmp/jpg, но я совершенно уверен, что вы можете найти всю необходимую информацию с помощью простого поиска в Google. Я говорю это, потому что у меня сейчас нет времени проверять это, но если вы хотите подождать, может быть, через несколько часов, у меня будет время. - person No Idea For Name; 04.08.2013

Поскольку формат изображения JPEG поддерживает только 8-битные цветовые компоненты (на самом деле стандарт допускает 12-битные компоненты, но я никогда не видел такой реализации), вы не можете сделать это с JPEG.

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

Компрессия нужна? Если не просто написать двоичный файл или сохранить файл в формате yml и т. д.

Если вам нужно сжатие, можно рассмотреть OpenEXR. Вероятно, Image Magick будет для вас лучшей реализацией, поскольку она хорошо интегрируется с CImg. Поскольку CImg изначально не поддерживает .jpg, я подозреваю, что у вас уже может быть Image Magick.

person Bull    schedule 04.08.2013
comment
Формат файла BMP (с которым у них все в порядке) не имеет сжатия, поэтому, вероятно, сжатие им не нужно. - person icktoofay; 04.08.2013
comment
Привет, на самом деле я не хотел использовать OpenCv в этом приложении, потому что с моей точки зрения это слишком тяжелая библиотека :-( - person user2485282; 04.08.2013
comment
@ user2485282 Я не уверен, что вы считаете неправильным с OpenCV - по моему опыту, это действительно быстро. А если по какой-то причине вы не хотите устанавливать всю библиотеку, вы всегда можете скопировать только исходники для кодека .bmp. - person Bull; 04.08.2013
comment
наверное ты прав, но я не могу найти ни одной библиотеки, кроме OpenCv, чтобы сделать это дело! Я хотел бы на самом деле понять код для этого, а не использовать библиотеку - person user2485282; 04.08.2013

Что ж, из вашего кода я вижу, что вы используете только 32-битные оттенки серого с плавающей запятой (без R, G, B, только I), так что вот мои предложения:

  1. Radiance RGBE (.hdr) использует 3x8-битную мантизу для R, G, B и 1x8-битную экспоненту, что дает вам только 16-битную точность. Но если вы используете также R, G, B, то для моделирования этот формат вам не подходит. (вы теряете большую точность из-за того, что показатель степени одинаков для всех каналов)

  2. любой формат HDR не является родным, поэтому вам необходимо установить программы просмотра и запрограммировать функции чтения/записи для исходного кода или использования библиотек.

  3. форматы без HDR (bmp, jpg, tga, png, pcx...) Если вы используете только оттенки серого, то это лучшее решение для вас. Эти форматы обычно 8-битные на канал, поэтому вы можете использовать 24-32-битные вместе для вашей одиночной интенсивности. Также вы можете просматривать/редактировать эти изображения на большинстве ОС. есть 2 способа сделать это.

    • для 32-битных изображений вы можете просто скопировать float в color =((DWORD*)(&col))[0]; где col — ваш плавающий пиксель. Это проще всего без потери точности, но если вы посмотрите на свое изображение, оно будет некрасивым :), потому что числа с плавающей запятой хранятся иначе, чем целые типы.

    • использование цветовой палитры. Создайте палитру цветовой шкалы от минимального до максимально возможного значения цветов вашего пикселя (больше цветов сохраняется с большей точностью). затем привязал все изображение к этим значениям. после этого преобразуйте значение с плавающей запятой в индекс в вашей палитре и сохраните его (для сохранения) и обратно получите значение с плавающей запятой из индекса в палитре из цвета (для загрузки), таким образом, изображение будет отображаться аналогично тепловым изображениям ... преобразование из плавающего значение для индекса / цвета RGB может быть выполнено линейно (с большой потерей точности) или нелинейно (с помощью функций exp, log или любой нелинейной, которую вы хотите). используйте нелинейное преобразование, чем вы потеряете только 25% точности (если вы действительно используете весь динамический диапазон с плавающей запятой, если нет, то потеря меньше даже до нуля)

советы по масштабу:

  • посмотрите на цвета спектра света, это хорошая цветовая шкала для начала (есть много простых исходных кодов, которые создают это с помощью некоторых для просто Google), вы также можете использовать любые шаблоны цветового градиента.

  • нелинейная функция должна меньше меняться в диапазоне с плавающей запятой, где вам нужно сохранять точность (диапазон, в котором может быть большинство ваших пикселей), и сильно меняться там, где точность не важна (+/- NaN). Я обычно использую exp, ln или tan, но вы должны масштабировать их в соответствии с вашей палитрой цветовой шкалы.

person Spektre    schedule 04.08.2013

Формат файла BMP довольно прост: https://en.m.wikipedia.org/wiki/BMP_file_format

Прочтите заголовок, чтобы определить высоту, ширину, бит на пиксель и начальный индекс данных. А затем просто начните заполнять свой массив с плавающей запятой, переводя значения пиксельного канала в число с плавающей запятой (начиная с индекса, указанного в заголовке), проходя по ширине. Когда вы достигнете модуля указанной ширины, перейдите к следующей строке в массиве.

Декодирование JPG является более сложным. Я бы посоветовал не пытаться сделать это самостоятельно.

person Hashman    schedule 05.08.2015

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

  • TIFF — для записи требуется библиотека

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

  • PFM (Portable Float Format), который является форматом с наименьшим общим знаменателем, в том же духе, что и формат NetPBM и который описан здесь.

Хорошей новостью является то, что CImg поддерживает PFM без дополнительных библиотек. Итак, ответ на ваш вопрос очень прост:

#include "CImg.h"
using namespace cimg_library;
int main() {
   CImg<float> image("image.png");
   image.normalize(0.0,1.0);
   image.save_pfm("result.pfm");
}

Если вы хотите просмотреть свое изображение позже, ImageMagick понимает все вышеперечисленные форматы и может преобразовать любой из них в любой другой:

convert result.pfm image.jpg       # convert PFM to JPG
convert result.pfm image.png       # convert PFM to PNG
convert result.tif image.bmp       # convert TIF to BMP

Ключевые слова: CImg, C++, C, с плавающей запятой, с плавающей запятой, изображение, обработка изображений, сохранить как с плавающей запятой, реальный, сохранить как реальный, 32-разрядный, PFM, Portable Float Map

person Mark Setchell    schedule 20.08.2017
comment
CImg сам может преобразовать файл pfm в другой формат? - person flaviu2; 02.12.2019