2016-08-19 4 views
0

В настоящее время я работаю над программой, помогающей фотографам создавать тайлапсы. Он вычисляет снижение или повышение яркости по серии изображений. Таким образом, изменение экспозиции и iso, например, не влияет на общее снижение яркости.Умножение значений пикселей в BufferedImage приводит к странному поведению

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

Это применяется при непосредственном воздействии BufferedImages, лежащего в основе DataBuffer.

В основном это работает, но я столкнулся с некоторыми изображениями, которые, похоже, имеют какую-то проблему.

У вас есть идея, почему это происходит?

public BufferedImage getImage(float mult){ 
    BufferedImage retim; 
    retim = new BufferedImage(img.getWidth(), img.getHeight(), img.getType()); 
    Graphics g = retim.getGraphics(); 
    g.drawImage(img, 0, 0, null); 
    g.dispose(); 

    DataBufferByte db = (DataBufferByte) retim.getRaster().getDataBuffer(); 
    byte[] bts = db.getData(); 
    for(int i=0;i<bts.length;i++){ 
     float n = bts[i]*mult; 
     if(n > 255){ 
      bts[i]= (byte) 255; 
     }else{ 
      bts[i] = (byte) n; 
     } 
    } 
    return retim; 
} 

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

This is the unwanted behaviour (on the left) and the expected on the right.

ответ

0

Ваша проблема эта линия, и это происходит из-за того, что Java byte s подписывались (в диапазоне [-128 ... 127]):

float n = bts[i] * mult; 

После умножения, ваш n переменная может быть отрицательной, что вызывает переполнение.

Чтобы исправить это, используйте битовую маску, чтобы получить значение как целое число без знака (в диапазоне [0 ... 255]), перед умножением на константу:

float n = (bts[i] & 0xff) * mult; 

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

Что-то вроде:

public BufferedImage getImage(float mult) { 
    return new RescaleOp(mult, 0, null).filter(img, null); 
} 
+1

Большое вам спасибо!Я уже пробовал реализовать псевдо-неподписанную версию java-байта, чтобы справиться с этим, но просто использование функции rescale работает намного лучше;) – I4k

0

Это связано с укупорки значения в определенных байтах в изображении.

Например (в предположении, RGB простой цветовое пространство):

Пиксель начинается (125,255,0), если умножить на коэффициент 2,0, результат (255,255,0). Это другой оттенок, чем оригинал.

Это также объясняется тем, что странные результаты возникают только в пикселях, у которых уже есть высокая яркость.

Этот link может помочь с лучшим алгоритмом настройки яркости.

Вы также можете обратиться к this related question.

+0

Спасибо за ваше предложение. Документ, на который вы указали, кажется, больше не доступен, но мне удалось найти его через waybackmachine. Хотя кажется, что метод, предложенный в этой статье, - это то, что я уже делаю, а именно умножение значений пикселей. – I4k