2016-08-19 82 views
0

我目前正在研究一个程序,以帮助摄影师创建timelapses。 它计算一系列图像的亮度下降或上升。所以曝光和iso的变化不会影响整体亮度的下降。在BufferedImage中乘以像素值导致奇怪的行为

为此,我使用一个简单的基于Swing的界面来显示第一张和最后一张图片。在它们下面是滑块来调整图像的亮度。

这是通过对DataBuffer底层的BufferedImages的直接操作来应用的。

大多数情况下,这种方法很有效,但我遇到了一些似乎有问题的图像。

你知道为什么会发生这种情况吗?

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; 

甲更好的解决方法,可能是使用RescaleOp,它可以在BufferedImages上进行亮度调整。

喜欢的东西:

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

非常感谢!我已经尝试过实现java字节的伪无符号版本来克服这个问题,但是简单地使用rescale op可以更好地工作;) – I4k

0

这是由于在图像中的某些字节的值的上限。

例如(假设RGB简单色彩空间):

像素开始于(125,255,0),如果通过因子2.0乘时,结果是(255,255,0)。这是一个不同于原来的色调。

这也是为什么奇怪的结果只出现在已经具有高亮度的像素开始。

这个link可能有助于更好的算法来调整亮度。您也可以参考this related question

+0

谢谢您的建议。你指出的论文似乎不再可用,但我通过waybackmachine找到了它。虽然看起来本文提出的方法是我已经做过的,即乘以像素值。 – I4k