我正在使用aparapi写一个Buddhabrot分形发生器。我使OpenCL部分工作,产生一个代表每个像素的单维数组。我将最终图像的维度作为最终的整数,并编写代码来获取该数组中任意点的索引。我想将此保存为图像,我正在尝试将BufferedImage与TYPE_USHORT_GRAY一起使用。这是我到目前为止所做的:
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设置为什么。我需要做什么?
答案 0 :(得分:7)
这里的问题是setRGB()
想要一个0xRRGGBB颜色值。无论数据存储的是什么,BufferedImage都喜欢假装图像是RGB。你实际上可以进入内部DataBufferShort
(使用getTile(0, 0).getDataBuffer()
),但要弄清楚它是如何布局的,这可能很棘手。
如果您已在short[]
中使用了像素,则更简单的解决方案可能是将它们复制到int[]
而不是将其插入MemoryImageSource
:
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));
这种方法的优点是可以控制底层像素阵列。您可以对该数组进行更改,然后在newPixels()
上调用MemoryImageSource
,它会更新为实时更新。除了灰度外,它还为您提供了定义自己的调色板的全部功能:
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);
但是,如果您想将其写入文件并保留每像素一个短格式(例如,加载到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);
答案 1 :(得分:3)
作为参考,此示例显示了两种不同的BufferedImage
类型如何解释相同的16位数据。您可以将鼠标悬停在图像上以查看像素值。
附录:要详细说明解释这个词,请注意setRGB()
尝试找到与给定ColorModel
中指定值最匹配的匹配项。
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();
}
});
}
}