16-битное цветное изображение Android в растровое изображение

Я пытаюсь получить 16-битное цветное изображение с разрешением 80 x 60 со встроенной камеры (техническое описание здесь). Я успешно могу получить 9600 (80*60*16/8) байт с камеры, но у меня проблема с отображением изображения. Я использую следующий код для преобразования массива байтов в растровое изображение:

bm = Bitmap.createBitmap(80, 60, Bitmap.Config.RGB_565);
bm.copyPixelsFromBuffer(ByteBuffer.wrap(jpegBytes));

jpegBytes — это массив байтов изображения длиной 9600 байт.

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

поврежденное изображение

99% времени. Однако я могу получить неповрежденные изображения, которые выглядят так:

неповрежденное изображение

очень редко. Есть ли у кого-нибудь предложения, почему это происходит? Огромное спасибо!

ОБНОВИТЬ:

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


person Ankit Goyal    schedule 23.07.2013    source источник
comment
Похоже, что структура изображения правильная, но цвета отключены. Вы уверены, что изображение всегда должно иметь формат RGB_565? Кроме того, вы уверены, что данные изображения представляют собой необработанные пиксели (а не, скажем, кодировку jpeg)?   -  person Ted Hopp    schedule 23.07.2013
comment
Согласно паспорту камеры, изображение должно передаваться в формате RGB_565. Мне удалось получить 4-битные и 8-битные изображения в градациях серого с камеры и отобразить их с помощью ARGB_8888, но приложение вылетает, когда я использую ARGB_8888 для отображения 16-битного изображения. Это связано с тем, что в 16-битном изображении на пиксель приходится 2 байта, а не 4 байта на пиксель, которые нужны ARGB_8888.   -  person Ankit Goyal    schedule 23.07.2013
comment
Возможно, это проблема порядка байтов. Что произойдет, если вы используете bm.copyPixelsFromBuffer(ByteBuffer.wrap(jpegBytes).order(ByteOrder.LITTLE_ENDIAN));?   -  person Ted Hopp    schedule 24.07.2013
comment
Я пробовал как Little Endian, так и Big Endian, но все равно получаю ту же испорченную картину.   -  person Ankit Goyal    schedule 24.07.2013
comment
Кажется, что все пиксели находятся в правильном месте, но их значения RGB перепутаны. Например, белая часть между обеими фотографиями одинакова, потому что порядок RGB не имеет значения для получения белого цвета. Однако ясно, что цвета перепутаны, потому что красный стул отображается синим на искаженном изображении, а синий рюкзак отображается зеленым на искаженном изображении.   -  person Ankit Goyal    schedule 24.07.2013


Ответы (2)


Использовать Config.ARGB_8888 в качестве конфигурации растрового изображения

Из документов для public static final Bitmap.Config RGB_565:

Каждый пиксель хранится в 2 байтах, и кодируются только каналы RGB: красный хранится с 5-битной точностью (32 возможных значения), зеленый хранится с 6-битной точностью (64 возможных значения) и синий хранится с 5-битной точностью. точность. Эта конфигурация может создавать небольшие визуальные артефакты в зависимости от конфигурации источника. Например, без сглаживания результат может иметь зеленоватый оттенок. Для получения лучших результатов следует применить дизеринг. Эта конфигурация может быть полезна при использовании непрозрачных растровых изображений, не требующих высокой точности цветопередачи.

person Sadegh    schedule 23.07.2013
comment
Если данные в буфере не имеют формата ARGB_8888 (что, по словам OP, это не так), это вообще не сработает. - person Ted Hopp; 23.07.2013
comment
Согласно паспорту камеры, на странице 8 указано что 16-битное цветное изображение передается как необработанное изображение 565 (RGB), поэтому Android RGB_565 теоретически должен работать. - person Ankit Goyal; 23.07.2013

У меня была аналогичная проблема, и вот как я ее решаю:

(1) Проверьте массив байтов, который вы получили, посмотрите, нужно ли вам сначала отменить его, прежде чем обернуть его в ByteBuffer.

(2) Проверьте порядок следования байтов в ByteBuffer, посмотрите, нужно ли вам изменить его на прямой порядок следования байтов (порядок байтов по умолчанию — обратный порядок байтов)

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

Псевдокод:

byte[] imageData ;  (byte array received)
reverseByteArray(imageData);

Bitmap bitmap = Bitmap.createBitmap(imgWidth, imgHeight,Bitmap.Config.RGB_565);

ByteBuffer buffer = ByteBuffer.wrap(imageData);
ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity());
newBuffer.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < buffer.capacity(); i++) {
            byte b = buffer.get(i);
            newBuffer.put(b);
        }
newBuffer.flip();
bitmap.copyPixelsFromBuffer(newBuffer);
setImage(bitmap);

//------
public static void reverseByteArray(byte[] array) {
        if (array == null) {
            return;
        }
        int i = 0;
        int j = array.length - 1;
        byte tmp;
        while (j > i) {
            tmp = array[j];
            array[j] = array[i];
            array[i] = tmp;
            j--;
            i++;
        }
    }
person Kelsea    schedule 07.08.2017