2016-08-19 10 views
0

私は現在、タイムラプスを作成しているフォトグラファーを支援するプログラムを開発中です。 一連の画像の輝度の低下または上昇を計算します。したがって、Exposureと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; 

Aまだ改善されていないのであれば、おそらくに明るさ調整を行うように作られたRescaleOpを使用することです。

のような何か:

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