为什么 raster.setPixels() 返回灰度图像
Why raster.setPixels() is returning a grayscale image
我在这里尝试用最快的方法将 3 个矩阵(R、G 和 B)保存到 BufferedImage 中。
我在 StackExchange 上找到了这个方法,但它对我不起作用,因为它是以灰度颜色保存的图像。
如果我做错了什么,或者如果有比 bufferimage.setRGB()
更快的方法,请帮助我。谢谢!
public static BufferedImage array_rasterToBuffer(int[][] imgR,
int[][]imgG, int[][] imgB) {
final int width = imgR[0].length;
final int height = imgR.length;
int numBandas = 3;
int[] pixels = new int[width*height*numBandas];
int cont=0;
System.out.println("max: "+width*height*3);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int band = 0; band < numBandas; band++) {
pixels[(((i*width)+j)*numBandas +band)] =Math.abs(( (imgR[i][j] & 0xff) >> 16 | (imgG[i][j] & 0xff) >> 8 | (imgB[i][j] & 0xff)));
cont+=1;
}
}
}
BufferedImage bufferImg = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
WritableRaster rast = (WritableRaster) bufferImg.getData();
rast.setPixels(0, 0, width, height, pixels);
bufferImg.setData(rast);
return bufferImg;
}
我觉得你变灰是因为表情
Math.abs(( (imgR[i][j] & 0xff) >> 16 | (imgG[i][j] & 0xff) >> 8 | (imgB[i][j] & 0xff)));
不依赖于band
,所以你的rgb值都是一样的。
表达式看起来很狡猾,因为在将 rgb 值打包成单个 int
.
时,您通常使用左移运算符 <<
我不确定,因为我不熟悉你正在使用的类,但我猜这样的东西可能有用
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixels[(((i*width)+j)*numBandas)] = imgR[i][j] & 0xFF;
pixels[(((i*width)+j)*numBandas + 1)] = imgG[i][j] & 0xFF;
pixels[(((i*width)+j)*numBandas + 2)] = imgB[i][j] & 0xFF;
}
}
如果你想要一个更快的方法,你需要从BufferedImage
中得到"live"WritableRaster
,并在图像的"native"格式中设置像素,这对于 TYPE_INT_RGB
是 "pixel packed"。这将为您节省多个(至少两个)数组副本和一些数据转换。它还将为您节省 2/3 的用于转换的内存,因为我们每个像素只需要一个数组组件。
下面的方法应该会快很多:
public static BufferedImage array_rasterToBuffer(int[][] imgR, int[][] imgG, int[][] imgB) {
final int width = imgR[0].length;
final int height = imgR.length;
// The bands are "packed" for TYPE_INT_RGB Raster,
// so we need only one array component per pixel
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// "Pack" RGB values to native TYPE_INT_RGB format
// (NOTE: Do not use Math.abs on these values, and without alpha there won't be negative values)
pixels[((y * width) + x)] = ((imgR[y][x] & 0xff) << 16 | (imgG[y][x] & 0xff) << 8 | (imgB[y][x] & 0xff));
}
}
BufferedImage bufferImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// NOTE: getRaster rather than getData for "live" view
WritableRaster rast = bufferImg.getRaster();
// NOTE: setDataElements rather than setPixels to avoid conversion
// This requires pixels to be in "native" packed RGB format (as above)
rast.setDataElements(0, 0, width, height, pixels);
// No need for setData as we were already working on the live data
// thus saving at least two expensive array copies
return bufferImg;
}
// Test method, displaying red/green/blue stripes
public static void main(String[] args) {
int[][] fooR = new int[99][99];
int[][] fooG = new int[99][99];
int[][] fooB = new int[99][99];
for (int i = 0; i < 33; i++) {
Arrays.fill(fooR[i], 0xff);
Arrays.fill(fooG[i + 33], 0xff);
Arrays.fill(fooB[i + 66], 0xff);
}
BufferedImage image = array_rasterToBuffer(fooR, fooG, fooB);
showIt(image);
}
// For demonstration only
private static void showIt(final BufferedImage image) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("JPEGTest");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JScrollPane scroll = new JScrollPane(new JLabel(new ImageIcon(image)));
scroll.setBorder(BorderFactory.createEmptyBorder());
frame.add(scroll);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
如果您不需要 "managed"(可能的显示硬件加速)图像,可以进一步优化它。诀窍是直接创建图像 "around" 您的 pixels
数组,从而在 setDataElements
中节省一次数组分配和数组复制。缺点是在某些情况下,图像在屏幕上的绘制速度会稍慢一些。不过,这主要是游戏或流畅动画的问题。
用以下代码替换从 BufferedImage bufferImg = new BufferedImage...
到 return
语句的行:
DataBufferInt buffer = new DataBufferInt(pixels, pixels.length);
int[] bandMasks = {0xFF0000, 0xFF00, 0xFF}; // RGB (no alpha)
WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, bandMasks, null);
ColorModel cm = new DirectColorModel(32,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0x00000000 // No Alpha
);
BufferedImage bufferImg = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
PS:请注意,我还更改了 x/y 循环内的移位,从右移位到左移位。可能只是一个小错字。 :-)
我在这里尝试用最快的方法将 3 个矩阵(R、G 和 B)保存到 BufferedImage 中。
我在 StackExchange 上找到了这个方法,但它对我不起作用,因为它是以灰度颜色保存的图像。
如果我做错了什么,或者如果有比 bufferimage.setRGB()
更快的方法,请帮助我。谢谢!
public static BufferedImage array_rasterToBuffer(int[][] imgR,
int[][]imgG, int[][] imgB) {
final int width = imgR[0].length;
final int height = imgR.length;
int numBandas = 3;
int[] pixels = new int[width*height*numBandas];
int cont=0;
System.out.println("max: "+width*height*3);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int band = 0; band < numBandas; band++) {
pixels[(((i*width)+j)*numBandas +band)] =Math.abs(( (imgR[i][j] & 0xff) >> 16 | (imgG[i][j] & 0xff) >> 8 | (imgB[i][j] & 0xff)));
cont+=1;
}
}
}
BufferedImage bufferImg = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
WritableRaster rast = (WritableRaster) bufferImg.getData();
rast.setPixels(0, 0, width, height, pixels);
bufferImg.setData(rast);
return bufferImg;
}
我觉得你变灰是因为表情
Math.abs(( (imgR[i][j] & 0xff) >> 16 | (imgG[i][j] & 0xff) >> 8 | (imgB[i][j] & 0xff)));
不依赖于band
,所以你的rgb值都是一样的。
表达式看起来很狡猾,因为在将 rgb 值打包成单个 int
.
<<
我不确定,因为我不熟悉你正在使用的类,但我猜这样的东西可能有用
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixels[(((i*width)+j)*numBandas)] = imgR[i][j] & 0xFF;
pixels[(((i*width)+j)*numBandas + 1)] = imgG[i][j] & 0xFF;
pixels[(((i*width)+j)*numBandas + 2)] = imgB[i][j] & 0xFF;
}
}
如果你想要一个更快的方法,你需要从BufferedImage
中得到"live"WritableRaster
,并在图像的"native"格式中设置像素,这对于 TYPE_INT_RGB
是 "pixel packed"。这将为您节省多个(至少两个)数组副本和一些数据转换。它还将为您节省 2/3 的用于转换的内存,因为我们每个像素只需要一个数组组件。
下面的方法应该会快很多:
public static BufferedImage array_rasterToBuffer(int[][] imgR, int[][] imgG, int[][] imgB) {
final int width = imgR[0].length;
final int height = imgR.length;
// The bands are "packed" for TYPE_INT_RGB Raster,
// so we need only one array component per pixel
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// "Pack" RGB values to native TYPE_INT_RGB format
// (NOTE: Do not use Math.abs on these values, and without alpha there won't be negative values)
pixels[((y * width) + x)] = ((imgR[y][x] & 0xff) << 16 | (imgG[y][x] & 0xff) << 8 | (imgB[y][x] & 0xff));
}
}
BufferedImage bufferImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// NOTE: getRaster rather than getData for "live" view
WritableRaster rast = bufferImg.getRaster();
// NOTE: setDataElements rather than setPixels to avoid conversion
// This requires pixels to be in "native" packed RGB format (as above)
rast.setDataElements(0, 0, width, height, pixels);
// No need for setData as we were already working on the live data
// thus saving at least two expensive array copies
return bufferImg;
}
// Test method, displaying red/green/blue stripes
public static void main(String[] args) {
int[][] fooR = new int[99][99];
int[][] fooG = new int[99][99];
int[][] fooB = new int[99][99];
for (int i = 0; i < 33; i++) {
Arrays.fill(fooR[i], 0xff);
Arrays.fill(fooG[i + 33], 0xff);
Arrays.fill(fooB[i + 66], 0xff);
}
BufferedImage image = array_rasterToBuffer(fooR, fooG, fooB);
showIt(image);
}
// For demonstration only
private static void showIt(final BufferedImage image) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("JPEGTest");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JScrollPane scroll = new JScrollPane(new JLabel(new ImageIcon(image)));
scroll.setBorder(BorderFactory.createEmptyBorder());
frame.add(scroll);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
如果您不需要 "managed"(可能的显示硬件加速)图像,可以进一步优化它。诀窍是直接创建图像 "around" 您的 pixels
数组,从而在 setDataElements
中节省一次数组分配和数组复制。缺点是在某些情况下,图像在屏幕上的绘制速度会稍慢一些。不过,这主要是游戏或流畅动画的问题。
用以下代码替换从 BufferedImage bufferImg = new BufferedImage...
到 return
语句的行:
DataBufferInt buffer = new DataBufferInt(pixels, pixels.length);
int[] bandMasks = {0xFF0000, 0xFF00, 0xFF}; // RGB (no alpha)
WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, bandMasks, null);
ColorModel cm = new DirectColorModel(32,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0x00000000 // No Alpha
);
BufferedImage bufferImg = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
PS:请注意,我还更改了 x/y 循环内的移位,从右移位到左移位。可能只是一个小错字。 :-)