public static BufferedImage split(BufferedImage img) {
BufferedImage pic = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = pic.getGraphics();
int width = 2000/2;
int height = 2000/2;
int imageW = pic.getWidth();
int imageH = pic.getHeight();
// Tile the image to fill our area.
for (int x = 0; x < width; x += imageW) {
for (int y = 0; y < height; y += imageH) {
g.drawImage(pic, x, y, null);
}
}
return pic ;
}
the point of the code is to create a tile of 2x2 of the image (same image reproduce at a smaller size in a 2x2 grid). i want to updated pic so i can print it onto a jpanel. all i get is black image. can someone tell me whats wrong with the code. or tell me how to create a better piece of code.
I want to make four smaller images of the original and place it in a grid of 2x2 that is the same size as the original image
Something like...
public static BufferedImage split(BufferedImage img) {
BufferedImage pic = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = pic.getGraphics();
int width = pic.getWidth() / 4;
int height = pic.getHeight() / 4;
Image scaled = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
// Tile the image to fill our area.
for (int x = 0; x < pic.getWidth(); x += width) {
for (int y = 0; y < pic.getHeight(); y += height) {
g.drawImage(scaled, x, y, null);
}
}
g.dispose();
return pic;
}
You may also like to have a look at Java: maintaining aspect ratio of JPanel background image and Quality of Image after resize very low -- Java for more details about how you can improve the scaling algorithm
Related
Tile seamless is an image operation that is available in GIMP. It transforms the image so that it can cover a surface smoothly with a repeatable pattern. The edges will not be visible and the pieces will fit perfectly when tiled together. It makes senses for grass, floors, walls, etc... As far as the example shown in the GIMP documentation though, it is not good (the Taj Mahal https://docs.gimp.org/2.10/en/gimp-filter-tile-seamless.html) but it gives an idea of how it works.
A transparent layer is applied over the image. It's a translation of half the size of the image (modulo image size) and the closer to the center, the more transparent it gets to show more of the original image. I took a look at the algorithm used in GIMP but it was pretty hard to read (https://gitlab.gnome.org/GNOME/gegl/-/blob/master/operations/common/tile-seamless.c).
So instead I remembered Pythagore to compute the distance to the center.
Then I apply a pro-rata to have an alpha between 0 and 255 :
0 => fully transparent => center
255 => fully opaque => corner
So here is the code :
public class TileSeamless {
public static BufferedImage createSeamlessTile(BufferedImage inputImage) {
int w = inputImage.getWidth();
int h = inputImage.getHeight();
BufferedImage seamlessTile = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
seamlessTile.getGraphics().drawImage(inputImage, 0, 0, null);
seamlessTile.getGraphics().drawImage(createLayerImage(inputImage), 0, 0, null);
return seamlessTile;
}
public static BufferedImage createLayerImage(BufferedImage inputImage) {
int w = inputImage.getWidth();
int h = inputImage.getHeight();
BufferedImage layerImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
Color color = new Color(inputImage.getRGB((x + w / 2) % w, (y + h / 2) % h));
int alpha = (int) Math.round(255 * distanceToCenter(x, y, w, h) / distanceToCenter(0, 0, w, h));
Color newColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
layerImage.setRGB(x, y, newColor.getRGB());
}
}
return layerImage;
}
public static double distanceToCenter(int x, int y, int w, int h) {
double distanceToCenterX = x - w / 2d;
double distanceToCenterY = y - h / 2d;
return Math.sqrt(distanceToCenterX * distanceToCenterX + distanceToCenterY * distanceToCenterY);
}
public static void main(String[] args) throws IOException {
File inputFile = new File(args[0]);
File outputFile = new File(args[1]);
BufferedImage inputImage = ImageIO.read(inputFile);
BufferedImage seamlessTile = TileSeamless.createSeamlessTile(inputImage);
ImageIO.write(seamlessTile, "png", outputFile);
}
The result is not too bad. It looks a bit different from the one produced by GIMP.
It's a bit blury.
Any idea how I can have a slighly more neat result?
For an automation tool I'm working on I need to compare 2 images.
My code works perfectly when I have "normal" images, but it fails when one of the images has a transparent area.
I'm reducing the color between the images for each pixel and creating a negative image that shows the difference. For images with transparent area the negative image is whole white, I can't see any shape or other info.
How to ignore the transparent area (shown in the images as gray color)?
My code:
private static BufferedImage createDiffImage(BufferedImage img1, BufferedImage img2) {
BufferedImage result = new BufferedImage(img1.getWidth(), img1.getHeight(), img1.getType());
int color;
for(int x = 0; x < img1.getWidth(); x++)
for(int y = 0; y < img1.getHeight(); y++) {
color = Math.abs(img2.getRGB(x, y) - img1.getRGB(x, y));
result.setRGB(x, y, color);
}
return result;
}
I found the solution:
private static BufferedImage createDiffImage(BufferedImage img1, BufferedImage img2) {
BufferedImage result = new BufferedImage(img1.getWidth(), img1.getHeight(), img1.getType());
for(int x = 0; x < img1.getWidth(); x++)
for(int y = 0; y < img1.getHeight(); y++) {
Color c1 = new Color(img1.getRGB(x,y));
Color c2 = new Color(img2.getRGB(x,y));
int alpha = 255;
int red = Math.abs(c1.getRed() - c2.getRed());
int green = Math.abs(c1.getGreen() - c2.getGreen());
int blue = Math.abs(c1.getBlue() - c2.getBlue());
Color negativeColor = new Color(red,green,blue, alpha);
result.setRGB(x, y, negativeColor.getRGB());
}
return result;
}
I have been stuck for a while with this issue. My idea or what I'd like to be able to do is take a BufferedImage and check to see if the BufferedImage contains a certain RGB value. If it has given RGB Value, then I want to remove that color completely from the image and making it transparent.
Here is my idea in code:
public static BufferedImage grabSubImage(BufferedImage image) {
Color backgroundToRemove = new Color(253, 28, 253);
int width = image.getWidth();
int height = image.getHeight();
for (int imageWidth = 0; imageWidth < width; imageWidth++) {
for (int imageHeight = 0; imageHeight < height; imageHeight++) {
int pixel = image.getRBG(imageWidth, imageHeight);
if (pixel == backgroundToRemove) image.removeBackgroundColor(); //Not an Actual Method
}
}
return image;
}
Here is my image:
http://i.stack.imgur.com/faEk1.png
The image in question is in: (4, 0) or since each box is 16 width px (16 * 4, 0)
Thanks for your help in advance! It's much appreciated!
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;
}
I'm attempting to take a picture as input, then manipulate said picture (I specifically want to make it greyscale) and then output the new image. This is a snippet of the code that I'm editing in order to do so but I'm getting stuck. Any ideas of what I can change/do next. Greatly appreciated!
public boolean recieveFrame (Image frame) {
int width = frame.width();
int height = frame.height();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
Color c1 = frame.get(i, j);
double greyScale = (double) ((Color.red *.3) + (Color.green *.59) + (Color.blue * .11));
Color newGrey = Color.greyScale(greyScale);
frame.set(i, j, newGrey);
}
}
boolean shouldStop = displayImage(frame);
return shouldStop;
}
I'm going to try to stick as close as possible to what you already have. So, I'll assume that you are looking for how to do pixel-level processing on an Image, rather than just looking for a technique that happens to work for converting to greyscale.
The first step is that you need the image to be a BufferedImage. This is what you get by default from ImageIO, but if you have some other type of image, you can create a BufferedImage and paint the other image into it first:
BufferedImage buffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffer.createGraphics();
g.drawImage(image, 0, 0);
g.dispose()
Then, you can operate on the pixels like this:
public void makeGrey(BufferedImage image) {
for(int x = 0; x < image.getWidth(); ++x) {
for(int y = 0; y < image.getHeight(); ++y) {
Color c1 = new Color(image.getRGB(x, y));
int grey = (int)(c1.getRed() * 0.3
+ c1.getGreen() * 0.59
+ c1.getBlue() * .11
+ .5);
Color newGrey = new Color(grey, grey, grey);
image.setRGB(x, y, newGrey.getRGB());
}
}
}
Note that this code is horribly slow. A much faster option is to extract all the pixels from the BufferedImage into an int[], operate on that, and then set it back into the image. This uses the other versions of the setRGB()/getRGB() methods that you'll find in the javadoc.