2011-01-12 1 views
5

Я пытаюсь применить фильтры смешивания на двух изображениях (в данном случае HardLight). HardLight не поддерживается в базовой библиотеке Android, поэтому я делаю это вручную на каждом пикселе. Первый запуск работает, но скорость меньше звездной. Создание изображения 500х500 из базового изображения 500х500 и фильтра 500х500 происходит слишком долго. Этот фрагмент кода используется для создания эскизов (72x72) и является неотъемлемой частью ядра приложения. Мне бы хотелось, чтобы некоторые советы и/или подсказки о том, как ускорить это.Оптимизация смешивания пикселей на Android Bitmaps

Если огромный выигрыш может быть сделан, если предположить, что ни один образ не будет иметь альфа, это нормально. ПРИМЕЧАНИЕ: BlendMode и alpha - значения, не используемые в примере (BlendMode будет выбирать тип blend, в этом случае я жестко закодированный HardLight).

public Bitmap blendedBitmap(Bitmap source, Bitmap layer, BlendMode blendMode, float alpha) { 
    Bitmap base = source.copy(Config.ARGB_8888, true); 
    Bitmap blend = layer.copy(Config.ARGB_8888, false); 

    IntBuffer buffBase = IntBuffer.allocate(base.getWidth() * base.getHeight()); 
    base.copyPixelsToBuffer(buffBase); 
    buffBase.rewind(); 

    IntBuffer buffBlend = IntBuffer.allocate(blend.getWidth() * blend.getHeight()); 
    blend.copyPixelsToBuffer(buffBlend); 
    buffBlend.rewind(); 

    IntBuffer buffOut = IntBuffer.allocate(base.getWidth() * base.getHeight()); 
    buffOut.rewind(); 

    while (buffOut.position() < buffOut.limit()) { 
     int filterInt = buffBlend.get(); 
     int srcInt = buffBase.get(); 

     int redValueFilter = Color.red(filterInt); 
     int greenValueFilter = Color.green(filterInt); 
     int blueValueFilter = Color.blue(filterInt); 

     int redValueSrc = Color.red(srcInt); 
     int greenValueSrc = Color.green(srcInt); 
     int blueValueSrc = Color.blue(srcInt); 

     int redValueFinal = hardlight(redValueFilter, redValueSrc); 
     int greenValueFinal = hardlight(greenValueFilter, greenValueSrc); 
     int blueValueFinal = hardlight(blueValueFilter, blueValueSrc); 

     int pixel = Color.argb(255, redValueFinal, greenValueFinal, blueValueFinal); 

     buffOut.put(pixel); 
    } 

    buffOut.rewind(); 

    base.copyPixelsFromBuffer(buffOut); 
    blend.recycle(); 

    return base; 
} 

private int hardlight(int in1, int in2) { 
    float image = (float)in2; 
    float mask = (float)in1; 
    return ((int)((image < 128) ? (2 * mask * image/255):(255 - 2 * (255 - mask) * (255 - image)/255))); 

} 
+0

Привет, вы можете помочь мне в том, как использовать альфа в этой функции? –

ответ

0

Был вопрос, как это некоторое время назад (Link). Я не уверен, что ОП когда-либо решал свою проблему.

Что я сделал в своем случае, чтобы достичь «комбинации фотошопов», было применено прозрачное наложение теней к одному цвету. Просто мой графический дизайнер выяснил, как сделать теневое оверлея. Это получилось великолепно, и я полностью проигнорировал проблему необходимости перебирать пиксели в растровом изображении (я использовал getPixels() и setPixels()). Жесткая часть была на самом деле у моих дизайнеров, но как только он понял это, у него появилось много красивых изображений.

В основном я использовал альфа-маску (для создания динамических цветов) с наложением тени. Я хотел бы узнать о решении через код, так что удачи вам!

Редактировать: Кроме того, я не знаком с BlendMode. Вы никогда не использовали его в своем методе. Что это такое, пользовательский класс?

+0

К сожалению, это решение не будет работать в моем случае. – MarkPowell

2

Операции с плавающей точкой, как правило, медленнее, чем целые, хотя я ничего не могу сказать об Android. Интересно, почему вы конвертируете ввод в hardlight в плавающую точку, когда операции выглядят так, как будто они отлично работают как целые числа?

Вы также можете получить ускорение, поместив формулу inline в цикл, вместо вызова функции. Или, может быть, нет, но стоит попробовать и провести бенчмаркинг.

+0

Пробуя разные вещи, я смог добиться увеличения производительности на 40% с помощью массивов int вместо буферов (используя 'getPixels()' и 'setPixels()') и не преобразовывать значения в float в 'hardlight' , Помимо этого, я думаю, что лучшая производительность, которую вы получите, это принять этот расчет на собственный уровень, возможно, реализовать пользовательский Xfermode. –

+0

hmm, переключение на getPixels()/setPixels() Я видел двойное вычисление времени, если я не понимаю, что вы говорите? – MarkPowell

+0

@MarkPowell, я думаю, что @Kevin спорил в пользу массивов int и спорил * с * getPixels/setPixels. Вам нужно будет направить свой комментарий на него, запустив его с @Kevin, если у вас появятся дополнительные вопросы. –

1

Кроме того, если вы можете пожертвовать 3 бит/пиксел конечного качества изображения/точности, - мы можем выиграть прирост производительности около 25% в функции HARDLIGHT(), переписав его с битовые операторы:

int hardlight(int image, int mask) { 
    return (((image < 128) ? 
      ((((mask << 1) * image) >> 8)): 
      (255^((((255^mask) << 1) * (255^image)) >> 8)))); 
} 
+0

Спасибо, видя, что с этим улучшается общая скорость на 10%. Тем не менее, придется посмотреть, возможна ли жертва 3 бит/пиксель. – MarkPowell

+0

Хорошо. Жаль, что прирост производительности составляет всего 10% вместо 25%, как в моей машине Windows.Я подозреваю, что побитовые операторы Android менее оптимизированы, чем по сравнению с компилятором Windows/MS VS C/C++. Или, может быть, основное узкое место в производительности не находится в функции функции подсветки, а где-то в другом месте. –