Nano Hash - криптовалюты, майнинг, программирование

Доступ к необработанным данным в ARGB_8888 Android Bitmap

Я пытаюсь получить доступ к необработанным данным растрового изображения в формате ARGB_8888 на Android, используя методы copyPixelsToBuffer и copyPixelsFromBuffer. Однако вызов этих вызовов, по-видимому, всегда применяет альфа-канал к каналам RGB. Мне нужны необработанные данные в байте [] или подобном (для прохождения через JNI; да, я знаю о bitmap.h в Android 2.2, не могу его использовать).

Вот пример:

    // Create 1x1 Bitmap with alpha channel, 8 bits per channel
    Bitmap one = Bitmap.createBitmap(1,1,Bitmap.Config.ARGB_8888);
    one.setPixel(0,0,0xef234567);
    Log.v("?","hasAlpha() = "+Boolean.toString(one.hasAlpha()));
    Log.v("?","pixel before = "+Integer.toHexString(one.getPixel(0,0)));

    // Copy Bitmap to buffer
    byte[] store = new byte[4];
    ByteBuffer buffer  = ByteBuffer.wrap(store);
    one.copyPixelsToBuffer(buffer);

    // Change value of the pixel
    int value=buffer.getInt(0);
    Log.v("?", "value before = "+Integer.toHexString(value));
    value = (value >> 8) | 0xffffff00;
    buffer.putInt(0, value);
    value=buffer.getInt(0);
    Log.v("?", "value after = "+Integer.toHexString(value));

    // Copy buffer back to Bitmap
    buffer.position(0);
    one.copyPixelsFromBuffer(buffer);
    Log.v("?","pixel after = "+Integer.toHexString(one.getPixel(0,0)));

Затем журнал показывает

hasAlpha() = true
pixel before = ef234567
value before = 214161ef
value after = ffffff61
pixel after = 619e9e9e

Я понимаю, что порядок каналов argb другой; хорошо. Но я не хочу, чтобы альфа-канал применялся к каждой копии (что, похоже, он и делает).

Так должны работать copyPixelsToBuffer и copyPixelsFromBuffer? Есть ли любой способ получить необработанные данные в byte[]?

Добавлено в ответ на ответ ниже:

Ввод buffer.order(ByteOrder.nativeOrder()); перед copyPixelsToBuffer действительно меняет результат, но все же не так, как я хочу:

pixel before = ef234567
value before = ef614121
value after = ffffff41
pixel after = ff41ffff

Кажется, страдает от одной и той же проблемы (альфа применяется к каждому copyPixelsFrom/ToBuffer).


  • Привет, я тоже столкнулся с этой проблемой. Вы нашли способ решить эту проблему? Может быть, способ преобразовать данные обратно в истинные значения RGB? 07.09.2012
  • Вы также можете проверить Bitmap.isPremultiplied(). Думаю, по умолчанию установлено значение true, когда присутствует альфа-канал. 12.01.2013
  • Вы пробовали Bitmap.getPixels()? В документации прямо сказано, что он возвращает неумноженные пиксели ARGB. Ниже также есть ответ о getPixels(), но вы не прокомментировали его. 20.01.2019

Ответы:


1

Я понимаю, что это очень устарело и, вероятно, не поможет вам сейчас, но недавно я столкнулся с этим, пытаясь заставить copyPixelsFromBuffer работать в моем приложении. (Спасибо, что задали этот вопрос, кстати! Вы сэкономили мне массу времени при отладке.) Я добавляю этот ответ в надежде, что он поможет другим, таким как я, в будущем...

Хотя я еще не использовал это, чтобы убедиться, что оно работает, похоже, что начиная с уровня API 19 у нас, наконец, появится способ указать не «применять альфу» (также известное как предварительное умножение) в пределах Bitmap. Они добавляют метод setPremultiplied(boolean), который должен помочь в подобных ситуациях в будущем, позволив нам указать false.

Надеюсь, это поможет!

15.03.2014
  • @KasperPeeters, хе-хе, спасибо! Я надеюсь это решит наши проблемы! 16.03.2014

  • 2

    Один из способов получить доступ к данным в Bitmap — использовать метод getPixels(). Ниже вы можете найти пример, который я использовал для получения изображения в градациях серого из данных argb, а затем обратно из массива байтов в растровое изображение (конечно, если вам нужен rgb, вы резервируете 3x байта и сохраняете их все...):

    /*Free to use licence by Sami Varjo (but nice if you retain this line)*/
    
    public final class BitmapConverter {
    
        private BitmapConverter(){};
    
       /**
        * Get grayscale data from argb image to byte array
        */
       public static byte[] ARGB2Gray(Bitmap img)
       {
    
           int width = img.getWidth();
           int height = img.getHeight();
    
           int[] pixels = new int[height*width];
           byte grayIm[] = new byte[height*width];
    
           img.getPixels(pixels,0,width,0,0,width,height);
    
           int pixel=0;
           int count=width*height;
    
           while(count-->0){
               int inVal = pixels[pixel];
    
               //Get the pixel channel values from int 
               double r = (double)( (inVal & 0x00ff0000)>>16 );
               double g = (double)( (inVal & 0x0000ff00)>>8  );
               double b = (double)(  inVal & 0x000000ff)      ;
    
               grayIm[pixel++] = (byte)( 0.2989*r + 0.5870*g + 0.1140*b );
           }
    
           return grayIm;
       }
    
       /**
        * Create a gray scale bitmap from byte array
        */
       public static Bitmap gray2ARGB(byte[] data, int width, int height)
       {
           int count = height*width;
           int[] outPix = new int[count];
           int pixel=0;
           while(count-->0){
               int val = data[pixel] & 0xff; //convert byte to unsigned
               outPix[pixel++] = 0xff000000 | val << 16 | val << 8 | val ;
           }
    
           Bitmap out =  Bitmap.createBitmap(outPix,0,width,width, height, Bitmap.Config.ARGB_8888);
           return out;
       }
    
    }
    
    23.10.2014

    3

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

    buffer.order(ByteOrder.nativeOrder());
    

    Посмотрите, поможет ли это.

    Более того, copyPixelsFromBuffer/copyPixelsToBuffer никаким образом не изменяет данные пикселей. Они копируются в сыром виде.

    15.02.2011
  • Это меняет результат, но не основную проблему: альфа-канал по-прежнему применяется для каждой копии (см. добавленное примечание в моем вопросе). 16.02.2011
  • Действительно, похоже, что copyPixelsToBuffer применяет альфа-канал к каналам RGB. Это хорошо видно, когда вы устанавливаетеPixel(0,0.0x7f224466) — это будет 0x7f332211 при чтении в буфер. Это может быть ошибка. Подумайте об этом. 16.02.2011

  • 4

    Это старый вопрос, но я столкнулся с той же проблемой и только что понял, что байт растрового изображения предварительно умножается, вы можете установить растровое изображение (начиная с API 19), чтобы не предварительно умножать буфер, а в API они не дают никакой гарантии.

    Из документов:

    public final void setPremultiplied(boolean premultiplied)

    Устанавливает, должно ли растровое изображение обрабатывать свои данные как предварительно умноженные. Растровые изображения всегда обрабатываются как предварительно умноженные системой представления и Canvas из соображений производительности. Хранение данных без предварительного умножения в растровом изображении (через setPixel, setPixels или BitmapFactory.Options.inPremultiplied) может привести к неправильному смешиванию, если оно отрисовано фреймворком.

    Этот метод не повлияет на поведение растрового изображения без альфа-канала или если hasAlpha() возвращает false.

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

    19.08.2016
    Новые материалы

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

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..