Java: Custom BufferedImage / More than RGBA - java

I want to save not only Red, Green, Blue and Alpha in my Image.
Every pixel also needs Z-Depth information, like, how far it was away from the camera.
Furthermore, I need to display the Image in a JFrame, so I can't use my custom Image class, but instead I need a BufferedImage or a subclass of it.
The Z-Depth shouldn't be visible in the JFrame. I just want to store it.
I've read much about the BufferedImage class.
I assume that I will have to extend classes like SampleModel or ColorModel, but I can't figure out how that should be done.
A nice solution would be to instantiate a new BufferedImage but with a custom Pixelclass that also stores depth, without actually extending the BufferedImage.
But any solution and any idea will be appreciated!
Does anybody know, which classes I have to extend, in order to save more information in every Pixel?

Well, I still don't understand why putting extra data into the BufferedImage would be more "flexible and extensible" in this case, so I'd probably just go with something like this myself:
public class DeepImage {
private final BufferedImage image;
private final float[] zIndex; // Must be image.width * image.height long
// TODO: Constructors and accessors as needed...
}
But of course, you could put the Z-depth into a BufferedImage, if you really like to:
public class DeepBufferedImage extends BufferedImage {
private final float[] zIndex;
public DeepImage(final BufferedImage image, final float[] zIndex) {
super(image.getColorModel(), image.getRaster(), image.getColorModel().isAlphaPremultiplied(), null);
if (zIndex.length != image.getWidth() * image.getHeight()) {
throw new IllegalArgumentException("bad zIndex length");
}
this.zIndex = zIndex; // Obviously not safe, but we'll go for performance here
}
public float getZ(int x, int y) {...};
public void setZ(int x, int y, float z) {...};
public float[] getZ(int x, int y, int w, int h) {...};
public void setZ(int x, int y, int w, int h, float[] z) {...};
}
The above class would work just like a normal BufferedImage for all cases, except it also happens to have a Z-index for each pixel.
Alternatively, you could make the Z-index part of the DataBuffer/SampleModel/Raster, but I think that would also require a custom ColorModel (or ColorSpace), and require quite a huge effort. These classes don't normally work well with "mixed" data types. Of course you could pack all your samples into one long per pixel, to avoid mixing data types:
long rgbaz = getRGB(x, y) << 32l | Float.toIntBits(getZ(x, y));
But, this would obviously kill performance.
So, in short, I just don't see the benefit from doing that. Especially as you don't want to visualize anything but the RGBA values, and there is also no file format I know of, that would support such a pixel layout*.
All of that said, there might still be a reason for you to implement this, I just don't see the need for it, given the requirements mentioned so far. Could of course be that I am missing something important. :-)
*) The TIFF format would support storing it, if you were using float samples for all 5 (R,G,B,A,Z) channels, or the packed long (64 bits) samples. However, I think it would be a lot simpler (and be a lot more compatible), to just store a normal 32 bit (8,8,8,8) RGBA image, and then a separate 1 channel float image in a multipage TIFF.

I believe that you are looking for ImageComponent3D with allows you to define an 3D array of pixels.
ImageComponent3D(int format, int width, int height, int depth)
Constructs an 3D image component object using the specified format, width, height and depth.
ImageComponent3D Documentation

Related

How to output the intensity of every point using imageJ?

I want the intensity of every point of a picture, which function should I call? Let say the pixels of my picture is 125 x 125, I want the intensity of (0,0) to (125,125), is there a function so that I give a coordinate, it will return me an intensity like this
function(0,123) --> intensity?
In ImageJ macro language:
result = getPixel(0,123);
print(result);
From other scripting languages, you can use the ImageJ Java API, e.g. the ImageProcessor#getPixel(int x, int y) method (ImageJ1) or the net.imglib2.Positionable#setPosition(int[] position) and net.imglib2.Sampler#get() methods (ImageJ2)
For example, in Python:
(using ImageJ1 structures)
from ij import IJ
imp = IJ.getImage()
result = imp.getProcessor().getPixel(0, 123)
print result
(using ImageJ2 structures and # parameter annotation)
# #Dataset img
ra = img.randomAccess()
ra.setPosition([0, 123])
result = ra.get()
print result
ImageJ uses the abstract class ImageProcessor, which is "roughly" an extension of the BufferedImage found into java.awt.
You can use one of the method proposed into the ImageProcessor:
public abstract int getPixel(int x, int y);
public abstract int get(int x, int y);
public abstract int get(int index);
But it gets a little bit messy when you want to access pixels encoding on multiple channels (colors images).
Here is a simple way to access pixels using the raster:
ImageProcessor myimage = ... ;
BufferedImage image = myimage.getBufferedImage() ;
int intensity = image.getRaster().getSample(0, 0, 0) ; // Get the value.
image.getRaster().setSample(0, 0, 0, NewValue) ; // Set a new value.
Thats the simplest way, but not the fastest. The fastest being the direct access to the values, which are stored into the DataBuffer, but then you have to deal with the type.

Why does VolatileImage have no set/getPixel() method

I am a relative newbie in game programming. I know how to draw pixels to a BufferedImage using setPixel(). It is horribly slow on larger formats so I moved on and found VolatileImage (took me a week or so). It is fairly easy to draw lines, strings, rects, etc but I can't draw individual pixels. I already tried using drawLine(x,y,x,y) but I get 3-4 FPS on an 800x600 image.
The fact that java didn't include setPixel() or setRGB() in the VolatileImage makes me pretty angry and confused.
I have 4 questions:
Is there a way to draw individual pixels on a VolatileImage? (on 1440x900 formats with FPS > 40)
Can I draw pixels in a BufferedImage with a faster method? (same 1440x900, FPS > 40)
Is there any other way to draw pixels fast enough for 3D games?
Can I make my BufferedImage hardware accelerated( tried using setAccelerationPriority(1F) but it doesn't work)
Please if you have any idea tell me. I can't continue making my game wihout this information. I already made 3D rendering algorithms but i need to be able to draw fast pixels. I have got a good feeling about this game.
Here's the code if it can help you help me:
public static void drawImageRendered (int x, int y, int w, int h) { // This is just a method to test the performance
int a[] = new int[3]; // The array containing R, G and B value for each pixel
bImg = Launcher.contObj.getGraphicsConfiguration().createCompatibleImage(800, 600); // Creates a compatible image for the JPanel object i am working with (800x600)
bImg.setAccelerationPriority(1F); // I am trying to get this image accelerated
WritableRaster wr = bImg.getRaster(); // The image's writable raster
for (int i = 0; i < bImg.getWidth(); i++) {
for (int j = 0; j < bImg.getHeight(); j++) {
a[0] = i % 256;
a[2] = j % 256;
a[1] = (j * i) % 256;
wr.setPixel(i, j, a); // Sets the pixels (You get a nice pattern)
}
}
g.drawImage(bImg, x, y, w, h, null);
}
I would much prefer not using OpenGL or any other external libraries, just plain Java.
Well you're basically drawing one pixel after the other using the CPU. There's no way that this can be accelerated, thus such a method does simply not make any sense for a VolatileImage. The low FPS you get suggest that this even causes a significant overhead, as each pixel drawing operation is sent to the graphics card (with information such as location & colour), which takes longer than to modify 3 or 4 bytes of RAM.
I suggest to either stop drawing each pixel separately or to figure out a way to make your drawing algorithm run directly on the graphics card (which most likely requires another language than Java).
It's been over 4 years since this post got an answer. I was looking for an answer to this question as well and stumbled on this post. After some more searching, I got it to work. Below I'll post the source to rendering pixels with a VolatileImage.
It seems Java hides our ability to plot pixels directly to a VolatileImage, but we can draw buffered images to it. For good reason. Using the software to plot a pixel doesn't really help with acceleration(in Java it seems). If you can plot pixels to a BufferedImage, and then render it on a VolatileImage, you may get a speed bonus since it's hardware accelerated from that point.
The source down below is a self-contained example. You can copy-pasta practically all of it to your project and run it.
https://github.com/Miekpeeps/JavaSnippets-repo/blob/master/src/graphics_rendering/pixels_03/PlottingVolatile.java
In the constructor I save the Graphics environment of the app/game.
private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
private GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
Then, when I call a method to enable hardware we create a buffer. I set the transparency to Opaque. In my little engine, I deal with transparency/alpha blending on another thread in the pipeline.
public void setHardwareAcceleration(Boolean hw)
{
useHW = hw;
if (hw)
{
vbuffer = gc.createCompatibleVolatileImage(width, height, Transparency.OPAQUE);
System.setProperty("sun.java2d.opengl", hw.toString()); // may not be needed.
}
}
For each frame I update, I get the Graphics from the VolatileImage and render my buffer there. Nothing gets rendered if I dont flush().
#Override
public void paintComponent(Graphics g)
{
if(useHW)
{
g = vbuffer.getGraphics();
g.drawImage(buffer, 0, 0, null);
vbuffer.flush();
}
else
{
g.drawImage(buffer, 0, 0, null);
buffer.flush();
}
}
There is still a little bit of overhead when calling to plot a pixel on the BufferedImage writable raster. But when we update the screen, we get a speed boost when using the Volatile image instead of using the Buffered image.
Hope this helps some folks out. Cheers.

BufferedImage: Set all pixels white where alpha = 0

I have a BufferedImage and would like to set all pixels that are fully transparent to be fully-transparent white (rather than transparent blank, or whatever may be in the source file). I can of course loop through the entire image using getRGB and setRGB, but is there some other way that would be much faster?
You can set the pixels like this:
public void setRGB(int startX,
int startY,
int w,
int h,
int[] rgbArray,
int offset,
int scansize)
This method sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) and default sRGB color space, into a portion of the image data. Color conversion takes place if the default model does not match the image ColorModel. There are only 8-bits of precision for each color component in the returned data when using this method. With a specified coordinate (x, y) in the this image, the ARGB pixel can be accessed in this way:
pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)];
I can't say for sure if it is faster, but take a look at the ColorConvertOp class.
I haven't used it personally, but it might be what you are looking for.

Retrieving color information from ColorPickerDialog.java

I'm currently using the ColorPickerDialog.java provided by Google. I can get it to load properly, and I can successfully choose a color, press the middle circle to confirm, and it will store it's information properly.
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.html
Since the dialog uses Canvas to draw its elements and the Paint class to color everything, is there a way to retrieve the RGB float value from the selection? I don't know if it's simple and I'm just missing it, but I'm not fully acquainted with Android yet.
If it helps to visualize what I'm trying to achieve, I'm using the ColorPickerDialog.java to let the user select a color, and I want to use that color to tint some things in OpenGL (so I need float r, float g, float b)
The Color class can handle these conversions. The integer you are handed back is a bitwise version usually encoded as ARGB but there are functions to split it up.
import android.graphics.Color;
public class ColorComponents implements OnColorChangedListener {
void colorChanged(int color) {
final int red = Color.red(color);
final int green = Color.green(color);
final int blue = Color.blue(color);
}
}

How to draw a two dimensional graphic at Java?

I have 2 different lists. Each of them holds x and y value pairs(they have both positive and negative values). How can I draw them on a 2D axis? I want to put points for every value and they will blue for first list and red for second list.
My lists' type:
List<List<Double>>
List<Double> inside of List<...> has 2 variables, first of it for x value and the second one is for y value.
However just I need to how to draw a two dimensional graphic at Java(desktop application) and put points wherever I want, improving code for my variables is less important.
PS:
I want the more and more simple of that kind of graphic:
Something like:
you could use a library like http://www.jfree.org/jfreechart/ (LGPL-License) there are lots of examples around the web, and it's quite easy to use.
here's an example, that seems to match your requirements:
http://www.java2s.com/Code/Java/Chart/JFreeChartMarkerDemo1.htm
Assuming you are using Swing with a panel, you can use the following:
public class JImagePanelExample extends JPanel {
private BufferedImage image;
private Graphics2D drawingBoard;
private int x, y; // Image position in the panel
// Let's assume image is a chart and you need to draw lines
public JImagePanelExample(BufferedImage image, int x, int y) {
super();
this.image = image;
// Retrieving a mean to draw lines
drawingBoard = image.createGraphics();
// Draw what you need to draw (see other methods too)
drawingBoard.drawLine(0, 10, 35, 55);
}
// Called by Swing to draw the image in the panel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, x, y, null);
}
}
If you don't want to use Swing and you just need to draw in 2D, focus on BufferedImage and Graphics2D only.
There is a Java 2D API: http://java.sun.com/products/java-media/2D/ and many charting libraries easily found with a web search.

Categories