Using DataBuffer of BufferedImage to set pixels - java

I am trying to use the underlying DataBufferByte of a BufferedImage of type TYPE_3BYTE_BGR to set pixel values as quick as possible.
Perhaps I am not understanding, but when I do the following...
byte[] imgBytes = ((DataBufferByte) img.getData().getDataBuffer()).getData();
... it seems as though I am getting a copy of the byte[] and not a reference. For example, if I run...
System.out.println(System.identityHashCode(imgBytes));
System.out.println(System.identityHashCode((DataBufferByte) img.getData().getDataBuffer()).getData());
... I get two clearly different object hashes. If I'm not mistaken, this indicates that I am not getting a reference to the underlying byte[] but rather a copy. If this is the case, how am I supposed to edit the DataBufferByte directly???
Or perhaps I am just setting the pixels wrong... When I set pixels in the imgBytes it doesn't seem to do anything to the BufferedImage. Once I get the byte[], I set each pixel value like so:
imgBytes[intOffset] = byteBlue;
imgBytes[intOffset+1] = byteGreen;
imgBytes[intOffset+2] = byteRed;
To me, this all seems fine. I can read pixels just fine this way so it seems I should be able to write them the same way!

I had the same problem. You may not use getData() but use getRaster() which gives you an array you can use to write to.

I once played around with pixel manipulations for Images in Java. Instead of directly answering your question I will offer an alternative solution to your problem. You can do the following to create an array of pixels to manipulate:
final int width = 800;
final int height = 600;
final int[] pixels = new int[width * height]; // 0xAARRGGBB
MemoryImageSource source = new MemoryImageSource(width, height, pixels, 0, width);
source.setAnimated(true);
source.setFullBufferUpdates(true);
Image image = Toolkit.getDefaultToolkit().createImage(source);
image.setAccelerationPriority(1f);
Then to draw the image, you can simply call the drawImage method from the Graphics class.
There are a few other ways to achieve what you are looking for, but this method was the simplest to me.

Here is how it's implemented in JDK7. You may have an error somewhere else if the stuff doesn't work for you.
public byte[] getData() {
theTrackable.setUntrackable();
return data;
}

Related

Adding BufferedImage objects into a Vector

I have a problem with a Vector of BufferedImage objects. I'm trying to add BufferedImage objects into the Vector but the Vector is always empty. The ImageIo.read(input1) seems not working but I don't understand why.
Here's a part of my code :
private void drawPixel(int index,String name) throws IOException {
File input1 = new File("pince.png");
BufferedImage img = ImageIO.read(input1);
Graphics g = this.imagePoints.getGraphics();
imagePixelLabelBuffered.add(img);
input1.delete();
changeColorPixelLabel(imagePixelLabelBuffered.get(labelClassesCount-1),labelClassesCount-1);
File output = new File("pince.png");
//ImageIO.write(imagePixelLabelBuffered.get(labelClassesCount-1), "PNG", output);
int x = (index % this.width);
int y = (index / this.width);
g.drawImage(imagePixelLabelBuffered.get(labelClassesCount-1),x-20, y-31,100,100, null);
repaint();
}
My guess is that file "pince.png" is not in the current directory. I would recommend you to put your images in the classpath, and load them via Class.getResource() or getResourceAsStream().
You add the BufferedImage to the vector using imagePixelLabelBuffered.add(img) and you never modify the variable img, so your problem is not with the vector or the BufferedImage.
I do think your problem is in the line changeColorPixelLabel(imagePixelLabelBuffered.get(labelClassesCount-1),labelClassesCount-1) and more particularly with labelClassesCount-1. This variable is never updated, and it is simply useless. You can use the following line:
changeColorPixelLabel(img, imagePixelLabelBuffered.size()-1);
In Java, a List has a method size that returns the number of elements in the list.
Moreover, you never modify the variable img, so it's still a pointer on the BufferedImage you add to the Vector.
If you don't do parallelized (multi-threaded) operations, use an ArrayList instead of a Vector. A Vector is an ArrayList with synchronized operations, which is slower.
Same thing with the line g.drawImage(imagePixelLabelBuffered.get(labelClassesCount-1),x-20, y-31,100,100, null), you can use the variable img.
[EDIT] Here is a link for BufferedImage cloning.

java - how to make an image using setRGB?

i have 2D array to keep color component value :
p[pixel_value][red]
p[pixel_value][green]
p[pixel_value][blue]
i just dont know how to use them to make an image.
i read about setRGB, what i understand is i should mix all of them to become a RGBArray. then how to make it?
is it any better way to make an image without setRGB ? i need some explanation.
The method setRGB() can be used to set the color of a pixel of an already existing image. You can open an already existing image and set all the pixels of it, using the values stored in your 2D array.
You can do it like this:
BufferedImage img = ImageIO.read(new File("image which you want to change the pixels"));
for(int width=0; width < img.getWidth(); width++)
{
for(int height=0; height < img.getHeight(); height++)
{
Color temp = new Color(p[pixel_value][red], p[pixel_value][green], p[pixel_value][blue]);
img.setRGB(width, height, temp.getRGB());
}
}
ImageIO.write(img, "jpg", new File("where you want to store this new image"));
Like this, you can iterate over all the pixels and set their color accordingly.
NOTE: By doing this, you will lose your original image. This is just a way which I know.
What you need is a BufferedImage. Create a BufferedImage of type TYPE_3BYTE_BGR, if RGB is what you want, with a specified width and height.
QuickFact:
The BufferedImage subclass describes an Image with an accessible
buffer of image data.
Then, call the getRaster() method to get a WritableRaster
QuickFact:
This class extends Raster to provide pixel writing capabilities.
Then, use the setPixel(int x, int y, double[] dArray) method to set the pixels.
Update:
If all you want is to read an image, use the ImageIO.read(File f) method. It will allow you to read an image file in just one method call.
Somewhat SSCCE:
BufferedImage img = null;
try {
img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {
}
You want to manually set RGB values?
You need to know that since an int is 32bit it contains all 4 rgb values (1 for the transparency).
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
^Alpha ^red ^green ^blue
You can accomplish using 4 int values by the use of binary arithmetic:
int rgb = (red << 16) && () (green << 8) & (blue);
bufferedImage.setRGB(x, y, rgb);
IN the above you can add Alpha as well if needed. You just "push" the binary codes into the right places.

Is multiplying a BufferedImage to set brightness the right thing?

This is a question, wether I am using the right way or not. And by the right way, I mean, is there a more memory-efficient way to do this?
I use 1 image source:
String imgurl = "imgreadertest8.png";
BufferedImage loadedimage = ImageIO.read(getClass().getResource(imgurl));
BufferedImage image = ImageIO.read(getClass().getResource(imgurl));
I draw the image in a paint() method. But sometimes I need to set the brightness:
public void setBrightness(float brightness)
{
RescaleOp rescaleOp = new RescaleOp(brightness, 15, null);
rescaleOp.filter(loadedimage, image);
}
So I read the same image, two times. One to have a 'final' BufferedImage (it's not really final... But I cannot use final in this context, because it needs to be used outside the constructor (which you can't see here, but it is)) which is used as template, and one to edit and draw.
More information: Before trying this way, I did this:
String imgurl = "imgreadertest8.png";
BufferedImage loadedimage = ImageIO.read(getClass().getResource(imgurl));
BufferedImage image = loadedimage;
But when I edit the image, it edits the loadedimage as well. Pretty much because they're the same object.
So... Is there another way to set the brightness of this image, WITHOUT loading the same image two times?
The following would copy an image.
public static BufferedImage copy(BufferedImage img) {
Hashtable<?,?> properties = new Hashtable<>();
for (String propertyName : img.getPropertyNames()) {
properties.put(propertyName, img.getProperty(propertyName));
}
return new BufferedImage(img.getColorModel(),
img.copyData(null),
img.isAlphaPremultiplied(), properties);
}
The same thing can be achieved slower but simplier by creating an empty image, drawing in the createGraphics of it (not to forget dispose). If you need a Graphics2D to process the image, that might be an option too.

Is there a function to sum the rasters of two buffered images?

I'm doing 2D filteing and want to do element by element addition on grayscale BufferedImages. Is there an existing function that will complete this for me or do i need to make one from scrach?
Is there some sort of matrix class that converts a raster to a matrix to simplyfy this problem?
Edit: here is the general gist of it
BufferedImageOp opX = new ConvolveOp(new Kernel(3,3, kernelX));
BufferedImageOp opY = new ConvolveOp(new Kernel(3,3, kernelY));
BufferedImage filtImageX = opX.filter(sourceImage, null);
BufferedImage filtImageY = opY.filter(sourceImage, null);
BufferedImage outputImage = addBufferedImages(filtImageX, filtImageY);
Grayscale Conversion:
public void toGrayscale() {
BufferedImageOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
sourceImage = op.filter(sourceImage, null);
}
I am not familiar with any java libs that do that for you.
You can get pixel at [i,j] with: image.getRGB(i, j);
BufferedImage image = ...;
BufferedImage resultImage = ...
int rgb= image.getRGB(i, j);
resultImage.setRGB(i, j, rgb);
You can also convert a buffered image to a byte array [ https://stackoverflow.com/a/7388025/1007845 ].
See this thread: how to convert image to byte array in java? to get a WritableRaster
EDIT:
It seems that WritableRaster might be useful in this case: http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/WritableRaster.html
WritableRaster raster = image.getRaster();
for(int h=0;h<height;h++) {
for(int w=0;w<width;w++) {
int colour = 127;
raster.setSample(w,h,0,colour);
}
}
I don't know of a direct way to do this.
But i can suggest a slightly underhanded approach. First, take your two images, and combine them into a single image with two bands. I'm hazy on the details of how to do this. I suspect you will want to create a Raster with a BandedSampleModel, and then blit the contents of the other two images into its DataBuffer. Although it looks like you should be able to create a two-bank DataBuffer which uses the arrays of the source images' (one-banked) DataBuffers as banks, which would avoid copying.
Once you have a two-band image, simply apply a BandCombineOp which sums the bands. You will need to express the summation as a matrix, but that shouldn't be hard. I think it would be [1.0, 1.0],or [0.5, 0.5] if you want to rescale the result.

Adjust brightness and contrast of BufferedImage in Java

I'm processing a bunch of images with some framework, and all I'm given is a bunch of BufferedImage objects. Unfortunately, these images are really dim, and I'd like to brighten them up and adjust the contrast a little.
Something like:
BufferedImage image = something.getImage();
image = new Brighten(image).brighten(0.3); // for 30%
image = new Contrast(image).contrast(0.3);
// ...
Any ideas?
That was easy, actually.
RescaleOp rescaleOp = new RescaleOp(1.2f, 15, null);
rescaleOp.filter(image, image); // Source and destination are the same.
A scaleFactor of 1.2 and offset of 15 seems to make the image about a stop brighter.
Yay!
Read more in the docs for RescaleOp.

Categories

Resources