Как отобразить HDR-изображение в Android?

Я делаю приложение для Android для распаковки, декодирования и отображения HDR-изображений.
Эти HDR-изображения используют 2 байта на компонент (A, R, G, B), поэтому один пиксель представлен 8-байтовым значением, которое может соответствовать только с длинным типом.

Я использую растровое изображение Android для отображения изображения, поскольку у них есть конструктор, позволяющий выполнять HDR с помощью Bitmap.Config.RGBA_F16:

int width = 1;
int height = 1;
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.RGBA_F16);

К сожалению, я не могу найти способ заполнить пиксель растрового изображения. Я использую рекомендуемую формулу, но ее нельзя использовать в методе setPixel(x,y,color) Bitmap, потому что цвет должен быть int:

long color = (A & 0xffff) << 48 | (B & 0xffff) << 32 | (G & 0xffff) << 16 | (R & 0xffff);
image.setPixel(0,0,color); //Argument type error

.
Я также пробовал использовать Color (с HDR совместимый метод), Paint и Canvas, но ни один метод Bitmap не принимает их для установки только одного пикселя.

Спасибо за любую помощь!


person Nicolas    schedule 01.04.2019    source источник
comment
Если вы занимаетесь редактированием изображений, вам все равно не следует использовать setPixel. Получите байты изображения и отредактируйте изображение напрямую. Повторные вызовы setPixel невероятно неэффективны.   -  person Gabe Sechan    schedule 01.04.2019
comment
@GabeSechan спасибо за ваш ответ, но он мне не помогает. Моя основная проблема заключается в отображении изображения размером 8 байт на пиксель в Android (если возможно с растровым изображением). Знаете ли вы какой-либо способ отображения HDR-контента (например, файла .hdr или потока байтов) на Android?   -  person Nicolas    schedule 01.04.2019
comment
Вся архитектура Android предназначена для ARGB с поддержкой меньших форматов (565, оттенки серого и т. д.). Вам придется снизить масштаб. Держу пари, именно это и делает найденный вами конструктор. Но если это заставит вас чувствовать себя лучше, это все равно должно произойти в какой-то момент — аппаратное обеспечение не будет поддерживать 16-битный вывод на канал на экране.   -  person Gabe Sechan    schedule 01.04.2019
comment
Затем мне трудно понять, почему видео HDR10 (10 бит на компонент) поддерживается Android на моем Galaxy Note 8, но не HDR-изображения. Документация по Android действительно неясна по этому поводу, к сожалению...   -  person Nicolas    schedule 01.04.2019
comment
Совершенно разные подсистемы. Видео использует OpenGL для прямой записи видеобуферов. На самом деле несопоставимо. Возможно, вы сможете использовать openGL напрямую, если вы делаете все через пользовательский вид или SurfaceView, но я не уверен, что это стоит усилий. В любом случае вы, скорее всего, не будете использовать объект Bitmap.   -  person Gabe Sechan    schedule 01.04.2019
comment
Ну, я думаю, что тогда мне придется замарать руки с OpenGL. Спасибо за ваше время и ответы, вы устранили большое недоразумение, которое у меня было!   -  person Nicolas    schedule 01.04.2019
comment
@Николас, ты нашел решение. Я столкнулся с той же проблемой - я нашел только информацию о том, как отображать видеоконтент hdr на Android: source.android.com/devices/tech/display/hdr   -  person 404pio    schedule 24.04.2020
comment
Я также нашел эту небольшую информацию: developer.android.com/reference/android/ графика/Bitmap.Config   -  person 404pio    schedule 24.04.2020
comment
@Nicolas Вы пытались использовать glide или загрузчик изображений Picasso вместо того, чтобы распаковывать изображение?   -  person Suresh Maidaragi    schedule 01.05.2020
comment
@ 404pio, к сожалению, мы не нашли никакого решения :( В качестве альтернативы мы использовали отображение тонов, чтобы уменьшить пространство пикселей до базовых 8 бит на компонент (используя преобразователи тонов opencv).   -  person Nicolas    schedule 12.05.2020


Ответы (1)


Если вам нужно открыть HDR-файл, например 16-битный png, а затем отобразить его, вы можете использовать ImageDecoder.setTargetColorSpace для создания растрового изображения в формате Bitmap.Config.RGBA_F16 следующим образом:

File file = new File(...);
ImageDecoder.Source source = ImageDecoder.createSource(file);
Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
    decoder.setTargetColorSpace(ColorSpace.Named.EXTENDED_SRGB);
});

Если вам нужно отобразить HDR-изображение, хранящееся в памяти, вы можете использовать Bitmap.copyPixelsFromBuffer, так как этот метод позволяет задавать пиксели растрового изображения без преобразования цветового пространства, как это делает Bitmap.setPixel. В этом случае вам нужно упаковать 4 канала, представленные значениями Half, в long для каждого пикселя, затем запишите эти длинные значения в Buffer и, наконец, скопируйте пиксели из буфер в растровое изображение.

LongBuffer buffer = LongBuffer.allocate(width * height);
for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        // fill pixels values as needed
        float r = (float)y / height;
        float g = (float)y / height;
        float b = (float)y / height;
        float a = 1f;
        long rBits = Half.halfToShortBits(Half.toHalf(r));
        long gBits = Half.halfToShortBits(Half.toHalf(g));
        long bBits = Half.halfToShortBits(Half.toHalf(b));
        long aBits = Half.halfToShortBits(Half.toHalf(a));
        long color = aBits << 48 | bBits << 32 | gBits << 16 | rBits;
        buffer.put(color);
    }
}
buffer.rewind();

bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGBA_F16);
bitmap.copyPixelsFromBuffer(buffer);

person fdermishin    schedule 22.12.2020