How can I remove the white pixels of an image before loading it in the Panel
the method for loading image in panel is:
public void ajouterImage(File fichierImage) {
// desiiner une image à l'ecran
try {
monImage = ImageIO.read(fichierImage);
} catch (IOException e) {
e.printStackTrace();
}
repaint();
}
You can't remove a pixel for say from an image, but you sure can change the color of it, or even make it transparent.
Let's say you have a pixel array as a variable somewhere, and you can give it the RGB value of your BufferedImage. The pixel array will be called pixels:
try {
monImage = ImageIO.read(fichierImage);
int width = monImage.getWidth();
int height = monImage.getHeight();
pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
for (int i = 0; i < pixels.length; i++) {
// I used capital F's to indicate that it's the alpha value.
if (pixels[i] == 0xFFffffff) {
// We'll set the alpha value to 0 for to make it fully transparent.
pixels[i] = 0x00ffffff;
}
}
} catch (IOException e) {
e.printStackTrace();
}
Assuming that by removing pixels you mean setting them to transparent, you need to set the alpha value of the image to zero. Here is a function colorToAlpha(BufferedImage, Color) which takes a BufferedImage and a Color as input and returns another BufferedImage with the Color set to transparent.
public static BufferedImage colorToAlpha(BufferedImage raw, Color remove)
{
int WIDTH = raw.getWidth();
int HEIGHT = raw.getHeight();
BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_ARGB);
int pixels[]=new int[WIDTH*HEIGHT];
raw.getRGB(0, 0, WIDTH, HEIGHT, pixels, 0, WIDTH);
for(int i=0; i<pixels.length;i++)
{
if (pixels[i] == remove.getRGB())
{
pixels[i] = 0x00ffffff;
}
}
image.setRGB(0, 0, WIDTH, HEIGHT, pixels, 0, WIDTH);
return image;
}
Example usage:
BufferedImage processed = colorToAlpha(rawImage, Color.WHITE)
Related
Is it possible to get the Color of a specific pixel of an Image?
I know how to get it from a BufferedImage:
Color color = new Color(bufferedImage.getRGB(x, y));
But that doesn't work with a java.awt.Image that looks for example like this:
Image image = null;
try {
image = ImageIO.read(new File("image.png"));
} catch (IOException e) {
e.printStackTrace();
}
Is there a way of doing it? Thanks in advance!
ImageIO.read(file) should return a BufferedImage. You can also use PixelGrabber to get a specific color. Example:
private static Color getSpecificColor(Image image, int x, int y) {
if (image instanceof BufferedImage) {
return new Color(((BufferedImage) image).getRGB(x, y));
}
int width = image.getWidth(null);
int height = image.getHeight(null);
int[] pixels = new int[width * height];
PixelGrabber grabber = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width);
try {
grabber.grabPixels();
} catch (InterruptedException e) {
e.printStackTrace();
}
int c = pixels[x * width + y];
int red = (c & 0x00ff0000) >> 16;
int green = (c & 0x0000ff00) >> 8;
int blue = c & 0x000000ff;
return new Color(red, green, blue);
}
ToolkitImage also has a method to get the BufferedImage but may return null: Why does ToolkitImage getBufferedImage() return a null?
http://www.rgagnon.com/javadetails/java-0257.html
What order does PixelGrabber put pixels into the array in java? Does it take the pixels along the width of the image first? Or along the height of the image first?
public static int[] convertImgToPixels(Image img, int width, int height) {
int[] pixel = new int[width * height];
PixelGrabber pixels = new PixelGrabber(img, 0, 0, width, height, pixel, 0, width);
try {
pixels.grabPixels();
} catch (InterruptedException e) {
throw new IllegalStateException("Interrupted Waiting for Pixels");
}
if ((pixels.getStatus() & ImageObserver.ABORT) != 0) {
throw new IllegalStateException("Image Fetch Aborted");
}
return pixel;
}
In the code example provided by the documentation
It has the following for loops:
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
handlesinglepixel(x+i, y+j, pixels[j * w + i]);
}
}
The access pixels[j * w + i] shows that it goes first along the row, then by along the columns. It grabs the pixels along the width first.
I'm pretty sure it uses row major order, but the easiest way is to actually grab the pixels, set a sequence of them to a particular color (for easy identification) and then save them out to an image. If the pixel strip appears vertical than the order is column major, otherwise it is row major. You can use code like: here
public static Image getImageFromArray(int[] pixels, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0,0,width,height,pixels);
return image;
}
To convert an the int[] to an image.
Also, I use ((DataBufferInt)img.grtRaster().getDataBuffer()).getData() to quickly grab the pixels of the image. Any modifications to that int[] will reflect in the image and vice versa. And that is row major for sure.
I have a buffered image that is drawn in grayscale, and I would like to convert it to color, where the colors map to some ranges in the gray. For example, all grays between 0-100 map to red, 100-255 map to green. It looks like the buffered image lookup ops are the way to do this, but I'm not entirely sure how to do this. For example, if the RGB of the grayscale image is (50,50,50), I want to convert that pixel to (255,0,0), not (255,255,255). Is the lookup op the right way to go with this?
if the RGB of the grayscale image is (50,50,50), I want to convert that pixel to (255,0,0)
Try this one
try {
BufferedImage image = ImageIO.read(new File("resources/Tulips.jpg"));
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
int newColorRGB = new Color(255, 0, 0).getRGB();
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
Color color = new Color(image.getRGB(x, y));
int red = color.getRed();
int blue = color.getBlue();
int green = color.getGreen();
if (red == 50 && blue == 50 && green == 50) {
newImage.setRGB(x, y, newColorRGB);
} else {
newImage.setRGB(x, y, color.getRGB());
}
}
}
ImageIO.write(newImage, "png", new File("resources/Tulips1.png"));
} catch (IOException e) {
e.printStackTrace();
System.out.println("Sorry, I cannot find that file.");
}
Note: change the image type as per your requirement.
I have been working with the polygon class and trying to set the pixel values inside of the polygon to transparent or remove them all together if this is possible, however I have hit a bit of a wall as I am trying to store the values as RGB int values and don't know how I would be able to make a pixel transparent/removed via this method.
Additionally to this I would also like to do the same thing but keeping pixels inside the polygon and deleting those outside if possible in order to be left with only the pixels contained within the polygon. I have searched around for this before but to no avail.
I did attempt to create a SSCCE for this to make it easier to work with and view for anyone taking the time to help however as its part of a much larger programme that I am working on creating one is proving to take some time, however once I have one working to better demonstrate this problem I will edit this post.
Thank you to anyone for taking the time to help me with this problem
Below I have some code for what I am currently using to segment the pixels that are contained within an already specified polygon. This is extremely similar to the way i do it for setting pixels outside the polygon to transparent only with the if statement arguments swapped around to remove a segment of the image and haveing a return for newImage rather than save image stuff and it works perfectly, however when I do it this way to save the pixels contained in the polygon it doesn't save for some reason.
public void saveSegment(int tabNum, BufferedImage img) {
segmentation = new GUI.Segmentation();
Polygon p = new Polygon();
Color pixel;
p = createPolygon(segmentation);
int height = img.getHeight();
int width = img.getWidth();
newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//loop through the image to fill the 2d array up with the segmented pixels
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
//If the pixel is inside polygon
if(p.contains(x, y) == true) {
pixel = new Color(img.getRGB(x, y));
//set pixel equal to the RGB value of the pixel being looked at
int r = pixel.getRed(); // red component 0...255
int g = pixel.getGreen(); // green component 0...255
int b = pixel.getBlue(); // blue component 0...255
int a = pixel.getAlpha(); // alpha (transparency) component 0...255
int col = (a << 24) | (r << 16) | (g << 8) | b;
newImage.setRGB(x, y, col);
}
else {
pixel = new Color(img.getRGB(x, y));
int a = 0; // alpha (transparency) component 0...255
int col = (a << 24);
newImage.setRGB(x, y, col);
}
}
}
try {
//then save as image once all in correct order
ImageIO.write(newImage, "bmp", new File("saved-Segment.bmp"));
JOptionPane.showMessageDialog(null, "New image saved successfully");
} catch (IOException e) {
e.printStackTrace();
}
}
An easier way is to use Java2D's clipping capability:
BufferedImage cutHole(BufferedImage image, Polygon holeShape) {
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(), image.getType());
Graphics2D g = newImage.createGraphics();
Rectangle entireImage =
new Rectangle(image.getWidth(), image.getHeight());
Area clip = new Area(entireImage);
clip.subtract(new Area(holeShape));
g.clip(clip);
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
BufferedImage clipToPolygon(BufferedImage image, Polygon polygon) {
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(), image.getType());
Graphics2D g = newImage.createGraphics();
g.clip(polygon);
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
How do I create an in-memory fully transparent SWT image and draw a black line on it with antialias enabled?
I expect the result to include only black color and alpha values ranging from 0 to 255 due to antialias...
I googled and tried everything that I could... is this possible at all?
This is how I did and it works:
Image src = new Image(null, 16, 16);
ImageData imageData = src.getImageData();
imageData.transparentPixel = imageData.getPixel(0, 0);
src.dispose();
Image icon = new Image(null, imageData);
//draw on the icon with gc
I was able to make this work, although it feels a bit hacky:
Display display = Display.getDefault();
int width = 10;
int height = 10;
Image canvas = new Image(display, width, height);
GC gc = new GC(canvas);
gc.setAntialias(SWT.ON);
// This sets the alpha on the entire canvas to transparent
gc.setAlpha(0);
gc.fillRectangle(0, 0, width, height);
// Reset our alpha and draw a line
gc.setAlpha(255);
gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
gc.drawLine(0, 0, width, height);
// We're done with the GC, so dispose of it
gc.dispose();
ImageData canvasData = canvas.getImageData();
canvasData.alphaData = new byte[width * height];
// This is the hacky bit that is making assumptions about
// the underlying ImageData. In my case it is 32 bit data
// so every 4th byte in the data array is the alpha for that
// pixel...
for (int idx = 0; idx < (width * height); idx++) {
int coord = (idx * 4) + 3;
canvasData.alphaData[idx] = canvasData.data[coord];
}
// Now that we've set the alphaData, we can create our
// final image
Image finalImage = new Image(canvasData);
// And get rid of the canvas
canvas.dispose();
After this, finalImage can be drawn into a GC with drawImage and the transparent parts will be respected.
I made it by allocating an ImageData, making it transparent then creating the Image from the data :
static Image createTransparentImage(Display display, int width, int height) {
// allocate an image data
ImageData imData = new ImageData(width, height, 24, new PaletteData(0xff0000,0x00ff00, 0x0000ff));
imData.setAlpha(0, 0, 0); // just to force alpha array allocation with the right size
Arrays.fill(imData.alphaData, (byte) 0); // set whole image as transparent
// Initialize image from transparent image data
return new Image(display, imData);
}
To scale with transparency, I've found that I have to manually set the alpha byte array as shown below. So the alpha ends up with nearest-neighbor anti aliasing.
public static Image scaleImage(Device device, Image orig, int scaledWidth, int scaledHeight) {
Rectangle origBounds = orig.getBounds();
if (origBounds.width == scaledWidth && origBounds.height == scaledHeight) {
return orig;
}
ImageData origData = orig.getImageData();
ImageData imData = new ImageData(scaledWidth, scaledHeight, origData.depth, origData.palette);
if (origData.alphaData != null) {
imData.alphaData = new byte[imData.width * imData.height];
for (int row = 0; row < imData.height; row++) {
for (int col = 0; col < imData.width; col++) {
int origRow = row * origData.height / imData.height;
int origCol = col * origData.width / imData.width;
byte origAlpha = origData.alphaData[origRow * origData.width + origCol];
imData.alphaData[row * imData.width + col] = origAlpha;
}
}
}
final Image scaled = new Image(device, imData);
GC gc = new GC(scaled);
gc.setAntialias(SWT.ON);
gc.setInterpolation(SWT.HIGH);
gc.setBackground(device.getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(0, 0, scaledWidth, scaledHeight);
gc.drawImage(orig, 0, 0, origBounds.width, origBounds.height, 0, 0, scaledWidth, scaledHeight);
gc.dispose();
return scaled;
}