2012-01-06 16 views
6

私はaparapiを使ってBuddhabrotフラクタルジェネレータを書いています。 OpenCLの一部を動作させて、各ピクセルを表す1次元配列にしました。私は最終的な画像の寸法を最終的なintとし、その配列内の任意の点のインデックスを得るためのコードを書いています。これを画像として保存したいと思い、TYPE_USHORT_GRAYでBufferedImageを使用しようとしています。これまで私が持っていたことは次のとおりです。短い[]をグレースケールの画像に変換する

BufferedImage image=new BufferedImage(VERTICAL_PIXELS, HORIZONTAL_PIXELS, BufferedImage.TYPE_USHORT_GRAY); 
    for(int i=0; i<VERTICAL_PIXELS; i++) 
     for(int k=0; k<HORIZONTAL_PIXELS; k++) 
      image.setRGB(k, i, normalized[getArrayIndex(k,i,HORIZONTAL_PIXELS)]); 

問題は、RGBをどのように設定するかわかりません。私は何をする必要がありますか?

答えて

7

ここで問題となるのは、setRGB()は0xRRGGBBのカラー値が必要です。 BufferedImageは、データが格納されているかどうかにかかわらず、イメージがRGBであるとふりをするのが好きです。あなたは実際に内部DataBufferShortgetTile(0, 0).getDataBuffer())に行くことができますが、それがどのようにレイアウトされているか把握するのは難しいことがあります。

すでにshort[]であなたのピクセルを持っている場合は、簡単な解決策はMemoryImageSourceにジャムに代わりint[]にそれをそれらをコピーすることがあります

int[] buffer = /* pixels */; 

ColorModel model = new ComponentColorModel(
    ColorSpace.getInstance(ColorSpace.CS_GRAY), new int[] { 16 }, 
    false, true, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); 

Image image = Toolkit.getDefaultToolkit().createImage(
    new MemoryImageSource(VERTICAL_PIXELS, HORIZONTAL_PIXELS, 
         model, buffer, 0, VERTICAL_PIXELS)); 

このアプローチの利点は、あなたがコントロールするということです下にある画素アレイ。その配列に変更を加えて、MemoryImageSourcenewPixels()と電話すると、ライブが更新されます。それはまた、あなたのグレースケール以外の独自のパレットを定義するための完全な力を与える:

int[] cmap = new int[65536]; 
for(int i = 0; i < 65536; ++i) { 

    cmap[i] = (((i % 10000) * 256/10000) << 16) 
      | (((i % 20000) * 256/20000) << 8) 
      | (((i % 40000) * 256/40000) << 0); 
} 
ColorModel model = new IndexColorModel(16, 65536, cmap, 0, false, -1, DataBuffer.TYPE_USHORT); 

あなただけの画面に画像を表示したい場合は、このアプローチはうまく動作します:

JFrame frame = new JFrame(); 
frame.getContentPane().add(new JLabel(new ImageIcon(image))); 
frame.pack(); 
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
frame.setVisible(true); 

しかし、あなたが望んでいた場合ファイルに書き出し、1ピクセルあたり1つの短いフォーマットを保持する(Matlabにロードするなど)場合、あなたは不運になります。あなたができることは、BufferedImageにペイントし、ImageIOでそれを保存することです。これはRGBとして保存されます。

あなたは間違いなく最後にBufferedImageが必要な場合は、別のアプローチは、自分でパレットの色を適用するRGB値を計算し、イメージにコピーすることです。この例が示すように、

short[] data = /* your data */; 
int[] cmap = /* as above */; 
int[] rgb = new int[data.length]; 

for(int i = i; i < rgb.length; ++i) { 
    rgb[i] = cmap[data[i]]; 
} 

BufferedImage image = new BufferedImage(
    VERTICAL_PIXELS, HORIZONTAL_PIXELS, 
    BufferedImage.TYPE_INT_RGB); 

image.setRGB(0, 0, VERTICAL_PIXELS, HORIZONTAL_PIXELS, 
    pixels, 0, VERTICAL_PIXELS); 
+0

私はその後、私の描画コードはどこにでもArrayOutOfBoundsの例外を除いてFUBARで実現、ということでした。それを見ると、うまくいくようです。私がやる必要があるのは、(うまくいけば)うまくいった.pngとして出力することだけです。これは問題ないと思われるので、これを正しいとマークします。 –

+0

これは、画像にピクセルを配置するとき、左から始まり、上から始まる右または水平に向かう垂直線で描画しますか?私の部分的に動作するコードは、時計回りに90度回転した画像を持っているので、私はそれが描画の失敗だとは思わない。 –

+0

心配しないで!私はMemoryImageSource部分の200をHORIZONTAL_PIXELSに変更しなければなりませんでした。ありがとう、ありがとう! –

3

参考のためにどのように2つの異なるBufferedImageタイプが同じ16ビットのデータを解釈するか。画像の上にマウスを置くと、ピクセル値が表示されます。

補遺:単語setRGB()試行が与えられたColorModelで指定された値に最も近いものを見つけるためにことに注意し、を解釈については詳しく説明し。

BufferedImageTest

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.image.BufferedImage; 
import java.util.Random; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

/** @see http://stackoverflow.com/questions/8765004 */ 
public class BufferedImageTest extends JPanel { 

    private static final int SIZE = 256; 
    private static final Random r = new Random(); 
    private final BufferedImage image; 

    public BufferedImageTest(int type) { 
     image = new BufferedImage(SIZE, SIZE, type); 
     this.setPreferredSize(new Dimension(SIZE, SIZE)); 
     for (int row = 0; row < SIZE; row++) { 
      for (int col = 0; col < SIZE; col++) { 
       image.setRGB(col, row, 0xff00 << 16 | row << 8 | col); 
      } 
     } 
     this.addMouseMotionListener(new MouseAdapter() { 

      @Override 
      public void mouseMoved(MouseEvent e) { 
       Point p = e.getPoint(); 
       int x = p.x * SIZE/getWidth(); 
       int y = p.y * SIZE/getHeight(); 
       int c = image.getRGB(x, y); 
       setToolTipText(x + "," + y + ": " 
        + String.format("%08X", c)); 
      } 
     }); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     g.drawImage(image, 0, 0, getWidth(), getHeight(), null); 
    } 

    static private void display() { 
     JFrame f = new JFrame("BufferedImageTest"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setLayout(new GridLayout(1, 0)); 
     f.add(new BufferedImageTest(BufferedImage.TYPE_INT_ARGB)); 
     f.add(new BufferedImageTest(BufferedImage.TYPE_USHORT_GRAY)); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       display(); 
      } 
     }); 
    } 
} 
+1

技術的に言えば、これらは同じ16ビットデータを表示していません - USHORTグレースケールまたはRGBのいずれかに強制変換すると同じRGB値を示しています。これは、setRGB()はイメージのパレットに色変換を行うためです。ピクセル値を書き込むだけではありません。それがピクセル値を書いた場合、グレースケールのものは下に白くなります。 –

+0

+1。作業例+画像付きの応答はいいです – Robin

+0

@RussellZahniserは正しいです。上記より。 – trashgod

関連する問題