0

I am currently working on a program to help photographers with the creation of timelapses. It calculates an decline or rise in brightness over a series of images. So the change in Exposure and iso for example dont affect the overall decline in brightness.

For this i use a simple Swing-based Interface which displays the first and last image. Under them are sliders to adjust the Brightness of the image.

This is applied via a direct manipulation of the BufferedImages underlying DataBuffer.

Mostly this works but i encountered some images which seem to have kind of a problem.

Do you have an idea why this is happening?

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 method which takes an float and multiplies every pixel in the image with it. (And some code to prevent the byte values from overflowing).

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

I4k
  • 5
  • 2

2 Answers2

0

This is due to the capping of the value in certain bytes in the image.

For example (assuming RGB simple colour space):

The pixel starts at (125,255,0), if you multiply by factor 2.0, the result is (255,255,0). This is a different hue than the original.

This is also why the strange results only occur on pixels that already have high brightness to start with.

This link may help with better algorithm for adjusting brightness.

You could also refer to this related question.

Community
  • 1
  • 1
RudolphEst
  • 1,240
  • 13
  • 21
  • Thank you for your suggestion. The paper you pointed to seems to be no longer available but i managed to find it via the waybackmachine. Although it seems as the method proposed in this paper is something i already do, namely multiplying pixel values. – I4k Aug 20 '16 at 08:03
0

Your problem is this line, and it occurs due to the fact that Java bytes are signed (in the range [-128...127]):

float n = bts[i] * mult;

After the multiplication, your n variable may be negative, thus causing the overflow to occur.

To fix it, use a bit mask to get the value as an unsigned integer (in the range [0...255]), before multiplying with the constant:

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

A better fix yet, is probably to use the RescaleOp, which is built to do brightness adjustments on BufferedImages.

Something like:

public BufferedImage getImage(float mult) {
    return new RescaleOp(mult, 0, null).filter(img, null);
}
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • 1
    Thank you so much! I already tried implementing a pseudo unsigned version of the java byte to overcome this but simply using the rescale op works a lot better ;) – I4k Aug 21 '16 at 17:37