Create different shaped pixel? - java

I was ready through Wikipedia about Pixel, I found out that a pixel can be rendered in different shapes, and not necessarily square shape.
How can I create image with different shaped pixels in Java?
Below is how I create an Image with Random pixels
/**
* File: RandomImage.java
*
* Description:
* Create a random color image.
*
* #author King Amada
* Date: 07-17-20148 tue
*/
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class RandomImage{
public static void main(String args[])throws IOException{
//image dimension
int width = 640;
int height = 320;
//create buffered image object img
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//file object
File f = null;
//create random image pixel by pixel
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int a = (int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
int p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
img.setRGB(x, y, p);
}
}
//write image
try{
f = new File("D:\\Image\\Output.png");
ImageIO.write(img, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
}//main() ends here
}//class ends here

Related

Graphics fill rect overflow into new rects?

I am trying to make a simple program to "pixelate" images. (make them look like 8 bit drawings). Basically how it works is that it loops through images in a given directory, asks for a percent of the width for a new "pixel" size, and then "pixelates" the image. It does this by looping through each new "pixel" and finding an average color for that square region and saving it to a 2D array of colors. Then it loops through the 2D array and draws rectangles on a new image that are the correct "pixel" size.
I'm having an issue with transparency in some of the pixels, and this is important because I want to be able to work with PNG files with transparent backgrounds. Here is what the before and after pictures look like:
Before and After. Obviously, the pixels that come after the centered image should still be transparent. I observed every "pixel"'s color and it shows that some are transparent even though they are being filled in black towards the bottom right of the picture. Here is my whole class:
package pixelator;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.imageio.ImageIO;
public class Pixelator {
public static void main(String[] args) throws IOException{
Scanner scan = new Scanner(System.in);
File folder = new File(args[0]);
File[] files = folder.listFiles();
if(files.length == 0) {
System.out.println("No files in given directory.");
}
for(int i = 0; i < files.length; i ++) {
if(filterFile(files[i])) {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
img = ImageIO.read(files[i]);
System.out.println("File: " + files[i].getName());
System.out.print("Enter pixelated size percentage(out of 100): ");
double percent = scan.nextDouble();
img = pixelate(img, percent);
File toWrite = new File(args[1] + "\\pixelated_" + files[i].getName());
ImageIO.write(img, files[i].getName().substring(files[i].getName().indexOf(".") + 1, files[i].getName().length()), toWrite);
System.out.println("New image saved");
}
}
}
/**
* returns a pixelated version of the original image with the pixels being the given percent
* if the image's size. Compensates for size of image.
* #param img
* #param percent
* #return BufferedImage
*/
public static BufferedImage pixelate(BufferedImage img, double percent) {
//find the number of pixels in the new "pixel"
int newPixelSize = (int)((percent/100.0) * img.getWidth());
int width = newPixelSize * (img.getWidth() / newPixelSize);
int height = newPixelSize * (img.getHeight() / newPixelSize);
System.out.println("Old Width: " + img.getWidth() + "\nOld Height: " + img.getHeight());
System.out.println("New pixel size: " + newPixelSize + "\nNew Width: " + width + "\nnew Height: " + height);
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Color[][] pixelArray = new Color[height / newPixelSize][width / newPixelSize];
for(int i = 0; i < pixelArray.length; i ++) {
for(int j = 0; j < pixelArray[0].length; j ++) {
pixelArray[i][j] = findColorAtPixelCoordinates(i, j, newPixelSize, img);
}
}
for(int i = 0; i < pixelArray.length; i ++) {
for(int j = 0; j < pixelArray[0].length; j ++) {
newImage = setNewImagePixel(i, j, newPixelSize, newImage, pixelArray[i][j]);
}
}
return newImage;
}
/**
* gets the average color over a certain rectangle on the original image
* #param y
* #param x
* #param pixelSize
* #param img
* #return
*/
public static Color findColorAtPixelCoordinates(int y, int x, int pixelSize, BufferedImage img) {
int[] averageARGB = {0, 0, 0, 0};
x = x * pixelSize;
y = y * pixelSize;
//loop through a certain "pixel" contained in the img, adding all of the values to the array
for(int i = y; i < y + pixelSize; i ++) {
for(int j = x; j < x + pixelSize; j++) {
Color colorAtPixel = new Color(img.getRGB(j, i), true);
averageARGB[0] += colorAtPixel.getRed();
averageARGB[1] += colorAtPixel.getGreen();
averageARGB[2] += colorAtPixel.getBlue();
averageARGB[3] += colorAtPixel.getAlpha();
}
}
//calculate the averages
averageARGB[0] = averageARGB[0] / (pixelSize * pixelSize);
averageARGB[1] = averageARGB[1] / (pixelSize * pixelSize);
averageARGB[2] = averageARGB[2] / (pixelSize * pixelSize);
averageARGB[3] = averageARGB[3] / (pixelSize * pixelSize);
return new Color(averageARGB[0], averageARGB[1], averageARGB[2], averageARGB[3]);
}
/**
* sets a new "pixel" rectangle for the new image. Also prints out each new "pixels: coordinates and color
* for testing
* #param y
* #param x
* #param pixelSize
* #param newImage
* #param color
* #return
*/
public static BufferedImage setNewImagePixel(int y, int x, int pixelSize, BufferedImage newImage, Color color) {
System.out.println("Row: "+ y + ", Column: " + x + ", Color: [" + color.getRed() + ", " + color.getGreen() + ", " + color.getBlue() + ", " + color.getAlpha()+"]");
x = x * pixelSize;
y = y * pixelSize;
// get the graphics then fill the rect with the right color
Graphics2D g = (Graphics2D) newImage.getGraphics();
g.setColor(color);
g.fillRect(x, y, x + pixelSize, y + pixelSize);
return newImage;
}
/**
* return true if the image is a png or jpg file
* #param fileName
* #return boolean
*/
public static boolean filterFile(File fileName) {
//System.out.println(fileName.substring(fileName.indexOf("."), fileName.length()));
if(!fileName.isFile()) {
return false;
}
return fileName.getName().substring(fileName.getName().indexOf("."), fileName.getName().length()).equals(".jpg") ||
fileName.getName().substring(fileName.getName().indexOf("."), fileName.getName().length()).equals(".jpeg") ||
fileName.getName().substring(fileName.getName().indexOf("."), fileName.getName().length()).equals(".png");
}
}
Thanks for any help you can provide!
First thing you are doing wrong is in function setNewImagePixel:
g.fillRect(x, y, x+pixelSize, y+pixelSize);
Instead of providing width and height, you are providing bottom right corner, So correct it using
g.fillRect(x, y, pixelSize, pixelSize);
Another thing is you should not average the alpha component in function findColorAtPixelCoordinates. You should write it as
Color color = new Color(img.getRGB(x, y), true);
averageARGB[3] = color.getAlpha();

Creating/Cropping image base on number of pixels Java

How can i crop an image to a specified number of pixels or create image that the output will be base on number of pixel not rectangular shape.
By using the code below i can only get square or rectangle shape.
BufferedImage out = img.getSubimage(0, 0, 11, 11);
But it only crops it to rectangular shape
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class raNd{
public static void main(String args[])throws IOException{
//image dimension
int width = 10;
int height = 10;
//create buffered image object img
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
//file object
File f = null;
//create random image pixel by pixel
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int a = 255;//(int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
int p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
img.setRGB(x, y, p);
}
}
//write image
try{
f = new File("/Users/kingamada/Documents/Java/Test6.png");
BufferedImage out = img.getSubimage(0, 0, 5, 2);
ImageIO.write(out, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
}//main() ends here
}//class ends here
Sample Picture
I want the last white pixels cropped out, so the picture will not be rectangle.
So assuming the number of pixels you need to keep is in variable int pixelsLimit;:
int pixels = 0;
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int p = 0;
if (pixels < pixelsLimit) {
int a = 255;//(int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
}
img.setRGB(x, y, p);
++pixels;
}
}
Java images are rectangular, but people have suggested you can set the pixels you don't want to be transparent.
Ellipse2D clip = new Ellipse2D.Double(0, 0, width, height);
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
if(!clip.contains(x,y)){
img.setRGB(x, y, 0);
}
}
}
This could directly be added to existing code to make your image an ellipse. Another way would be to use a clipping shape and a graphics object. I've replaced your complete write image block.
//write image
try{
f = new File("Test6.png");
Ellipse2D clip = new Ellipse2D.Double(0, 0, width, height);
BufferedImage clipped = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = clipped.getGraphics();
g.setClip(clip); //ellipse from above.
g.drawImage(img, 0, 0, null);
g.dispose();
ImageIO.write(clipped, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
This compiled for me and wrote a tiny circular image.

Copying the pixels of an image to a canvas in java

EDIT: I've changed some of my code to reflect what AlamasB said. I still don't understand how I should be populating my byte array and what conversions I need to do.
I'm trying to manipulate the pixels of an image uploaded by the user and write the new image onto a canvas. Right now I'm just trying to copy the original image without changing the RGB of the pixels. I've been stuck in the same spot for quite a while now and can't figure out where to go next. In the first section of the code I make a copy of the original image uploaded by the user.
Image image = imageView.getImage();
PixelReader pixelReader = image.getPixelReader();
PixelFormat format = pixelReader.getPixelFormat();
int width= (int)image.getWidth();
int height = (int) image.getHeight();
GraphicsContext gc = canvas.getGraphicsContext2D();
PixelWriter pw = gc.getPixelWriter();
byte[] imageData = new byte[width * height * 4];
imageData = createImageData(imageData, pixelReader, width, height);
//..
//...the next function populates my byte array with what's in the image
public byte[] createImageData(byte[] imageData, PixelReader pr, int width, int height){
int i = 0;
for(int y=0; y<height; y++){
for(int x = 0; x < width; x++){
int argb = pixelReader.getArgb(x, y);
imageData[i] = (byte) argb;
imageData[i+1] = (byte) argb;
imageData[i+2] = (byte) argb;
i+=3;
pw.setArgb(x, y, argb);
}
}
return imageData;
}
EDIT: No longer using this function. The next function is really confusing me. I'm referring to this http://docs.oracle.com/javafx/2/image_ops/jfxpub-image_ops.htm as a reference but I can't figure out what's going on.
//...
//... the next function sets the pixels of the canvas to what's in the byte array
public void drawImageData(byte[] imageData, PixelWriter pw, int width, int height){
boolean on = true;
PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteRgbInstance();
for(int y = 50; y < 150; y+=height){
for(int x = 50; x < 150; x+=width){
if(on){
pw.setPixels(x, y, width, height, pixelFormat, imageData, 0, width*3);
}
on = !on;
}
on=!on;
}
}
Considering that PixelReader provides getARGB your best bet in this case is probably to use 32-bit representation. Subsequently converting it to a 4-byte array, i.e. width * height * 4. Finally use setARGB to draw the image.
int argb = pixelReader.getArgb(x, y);
// populate imageData[i,i+1,i+2,i+3] by converting argb
...
// convert imageData[i,i+1,i+2,i+3] into a 32bit argb, say int argb2
pixelWriter.setArgb(x, y, argb2);
Alternatively, you can use Color's getOpacity() to get the A from RGBA. Again, using the 32-bit representation.
At the very least this will provide you with a minimal working example, which you can then extend.
Here's a quick version (self-contained, just copy and paste):
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.*;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class ImageManipulationApp extends Application {
private static final int APP_W = 800;
private static final int APP_H = 600;
private Parent createContent() {
Image image = makeMockImage();
byte[] imageData = imageToData(image);
byte[] modifiedImageData = modify(imageData);
Image modifiedImage = dataToImage(modifiedImageData);
HBox root = new HBox(25);
root.getChildren().addAll(new ImageView(image), new ImageView(modifiedImage));
return root;
}
private Image makeMockImage() {
WritableImage image = new WritableImage(APP_W / 2, APP_H);
PixelWriter writer = image.getPixelWriter();
for (int y = 0; y < APP_H; y++) {
for (int x = 0; x < APP_W / 2; x++) {
writer.setColor(x, y, Math.random() < 0.00005 ? Color.YELLOW : Color.BLACK);
}
}
return image;
}
/**
* Modifies the pixel data.
*
* #param data original image data
* #return modified image data
*/
private byte[] modify(byte[] data) {
// this is where changes happen
return data;
}
private byte[] imageToData(Image image) {
int width = (int) image.getWidth();
int height = (int) image.getHeight();
byte[] data = new byte[width * height * 4];
int i = 0;
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++){
int argb = image.getPixelReader().getArgb(x, y);
byte[] pixelData = ByteBuffer.allocate(4).putInt(argb).array();
data[i++] = pixelData[0];
data[i++] = pixelData[1];
data[i++] = pixelData[2];
data[i++] = pixelData[3];
}
}
return data;
}
private Image dataToImage(byte[] data) {
// if we don't know the image size beforehand we can encode width and height
// into image data too
WritableImage image = new WritableImage(APP_W / 2, APP_H);
PixelWriter writer = image.getPixelWriter();
int i = 0;
for (int y = 0; y < APP_H; y++) {
for (int x = 0; x < APP_W / 2; x++) {
int argb = ByteBuffer.wrap(Arrays.copyOfRange(data, i, i + 4)).getInt();
writer.setArgb(x, y, argb);
i += 4;
}
}
return image;
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Make a jpg a Shape [duplicate]

I was wondering whether there is any way to convert an image/graphic into a Shape? For example, can I convert the outline of a motorcycle shape into a Shape so I can then use it in Java? I know you can do it with normal squares or with rounded corners, polygons, etc. But is there a way to do a custom shape?
motorcycle.jpg
motorcycle-03.png
ImageOutline.java
This code requires some patience (when running).
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.geom.Area;
import javax.imageio.ImageIO;
import java.io.File;
import java.util.Date;
import javax.swing.*;
/* Motorcycle image courtesy of ShutterStock
http://www.shutterstock.com/pic-13585165/stock-vector-travel-motorcycle-silhouette.html */
class ImageOutline {
public static Area getOutline(BufferedImage image, Color color, boolean include, int tolerance) {
Area area = new Area();
for (int x=0; x<image.getWidth(); x++) {
for (int y=0; y<image.getHeight(); y++) {
Color pixel = new Color(image.getRGB(x,y));
if (include) {
if (isIncluded(color, pixel, tolerance)) {
Rectangle r = new Rectangle(x,y,1,1);
area.add(new Area(r));
}
} else {
if (!isIncluded(color, pixel, tolerance)) {
Rectangle r = new Rectangle(x,y,1,1);
area.add(new Area(r));
}
}
}
}
return area;
}
public static boolean isIncluded(Color target, Color pixel, int tolerance) {
int rT = target.getRed();
int gT = target.getGreen();
int bT = target.getBlue();
int rP = pixel.getRed();
int gP = pixel.getGreen();
int bP = pixel.getBlue();
return(
(rP-tolerance<=rT) && (rT<=rP+tolerance) &&
(gP-tolerance<=gT) && (gT<=gP+tolerance) &&
(bP-tolerance<=bT) && (bT<=bP+tolerance) );
}
public static BufferedImage drawOutline(int w, int h, Area area) {
final BufferedImage result = new BufferedImage(
w,
h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = result.createGraphics();
g.setColor(Color.white);
g.fillRect(0,0,w,h);
g.setClip(area);
g.setColor(Color.red);
g.fillRect(0,0,w,h);
g.setClip(null);
g.setStroke(new BasicStroke(1));
g.setColor(Color.blue);
g.draw(area);
return result;
}
public static BufferedImage createAndWrite(
BufferedImage image,
Color color,
boolean include,
int tolerance,
String name)
throws Exception {
int w = image.getWidth();
int h = image.getHeight();
System.out.println("Get Area: " + new Date() + " - " + name);
Area area = getOutline(image, color, include, tolerance);
System.out.println("Got Area: " + new Date() + " - " + name);
final BufferedImage result = drawOutline(w,h,area);
displayAndWriteImage(result, name);
return result;
}
public static void displayAndWriteImage(BufferedImage image, String fileName) throws Exception {
ImageIO.write(image, "png", new File(fileName));
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(image)));
}
public static void main(String[] args) throws Exception {
final BufferedImage outline = ImageIO.read(new File("motorcycle.jpg"));
BufferedImage crop = outline.getSubimage(17,35,420,270);
displayAndWriteImage(crop, "motorcycle-01.png");
BufferedImage crude = createAndWrite(crop, Color.white, false, 60, "motorcycle-02.png");
BufferedImage combo = createAndWrite(crude, Color.red, true, 0, "motorcycle-03.png");
}
}
function getArea_FastHack is build upon Andrew Thompsons work, which was very helpful.
Mine should be faster, however:
(//Edit: and sloppier, too)
import java.awt.*;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
/**
* CustomShape
* based on a Class from Andrew Thompson *
* Source: http://stackoverflow.com/questions/7052422/image-graphic-into-a-shape-in-java/7059497#7059497
* #author Samuel Schneider, Andrew Thompson
*
*
*/
class CustomShape {
private BufferedImage image=null;
/**
* Creates an Area with PixelPerfect precision
* #param color The color that is draws the Custom Shape
* #param tolerance The color tolerance
* #return Area
*/
public Area getArea(Color color, int tolerance) {
if(image==null) return null;
Area area = new Area();
for (int x=0; x<image.getWidth(); x++) {
for (int y=0; y<image.getHeight(); y++) {
Color pixel = new Color(image.getRGB(x,y));
if (isIncluded(color, pixel, tolerance)) {
Rectangle r = new Rectangle(x,y,1,1);
area.add(new Area(r));
}
}
}
return area;
}
public Area getArea_FastHack() {
//Assumes Black as Shape Color
if(image==null) return null;
Area area = new Area();
Rectangle r;
int y1,y2;
for (int x=0; x<image.getWidth(); x++) {
y1=99;
y2=-1;
for (int y=0; y<image.getHeight(); y++) {
Color pixel = new Color(image.getRGB(x,y));
//-16777216 entspricht RGB(0,0,0)
if (pixel.getRGB()==-16777216) {
if(y1==99) {y1=y;y2=y;}
if(y>(y2+1)) {
r = new Rectangle(x,y1,1,y2-y1);
area.add(new Area(r));
y1=y;y2=y;
}
y2=y;
}
}
if((y2-y1)>=0) {
r = new Rectangle(x,y1,1,y2-y1);
area.add(new Area(r));
}
}
return area;
}
public static boolean isIncluded(Color target, Color pixel, int tolerance) {
int rT = target.getRed();
int gT = target.getGreen();
int bT = target.getBlue();
int rP = pixel.getRed();
int gP = pixel.getGreen();
int bP = pixel.getBlue();
return(
(rP-tolerance<=rT) && (rT<=rP+tolerance) &&
(gP-tolerance<=gT) && (gT<=gP+tolerance) &&
(bP-tolerance<=bT) && (bT<=bP+tolerance) );
}
public CustomShape(String path) {
try {
BufferedImage image = ImageIO.read(new File(path));
this.image = image;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here's something faster but less accurate, useful for collision checking or 2D physics.
Point[] MakePoly(BufferedImage spr,int d,int angle){
//creates an outline of a transparent image, points are stored in an array
//arg0 - BufferedImage source image
//arg1 - Int detail (lower = better)
//arg2 - Int angle threshold in degrees (will remove points with angle differences below this level; 15 is a good value)
// making this larger will make the body faster but less accurate;
int w= spr.getWidth(null); int h= spr.getHeight(null);
// increase array size from 255 if needed
int[] vertex_x=new int[255], vertex_y=new int[255], vertex_k=new int[255];
int numPoints=0, tx=0,ty=0,fy=-1,lx=0,ly=0; vertex_x[0]=0; vertex_y[0]=0; vertex_k[0]=1;
for (tx=0;tx<w;tx+=d) for (ty=0;ty<h;ty+=1) if((spr.getRGB(tx,ty)>>24) != 0x00 )
{vertex_x[numPoints]=tx; vertex_y[numPoints]=h-ty; vertex_k[numPoints]=1; numPoints++; if (fy<0) fy=ty; lx=tx; ly=ty; break; }
for (ty=0;ty<h;ty+=d) for (tx=w-1;tx>=0;tx-=1) if((spr.getRGB(tx,ty)>>24) != 0x00 && ty > ly)
{vertex_x[numPoints]=tx; vertex_y[numPoints]=h-ty; vertex_k[numPoints]=1; numPoints++; lx=tx; ly=ty; break; }
for (tx=w-1;tx>=0;tx-=d) for (ty=h-1;ty>=0;ty-=1) if((spr.getRGB(tx,ty)>>24) != 0x00 && tx < lx)
{vertex_x[numPoints]=tx; vertex_y[numPoints]=h-ty; vertex_k[numPoints]=1; numPoints ++; lx=tx; ly=ty; break; }
for (ty=h-1;ty>=0;ty-=d) for (tx=0;tx<w;tx+=1) if((spr.getRGB(tx,ty)>>24) != 0x00 && ty < ly && ty > fy)
{vertex_x[numPoints]=tx; vertex_y[numPoints]=h-ty; vertex_k[numPoints]=1; numPoints ++; lx=tx; ly=ty; break; }
double ang1,ang2; for (int i=0;i<numPoints-2;i++) {
ang1 = PointDirection(vertex_x[i],vertex_y[i], vertex_x[i+1],vertex_y[i+1]);
ang2 = PointDirection(vertex_x[i+1],vertex_y[i+1], vertex_x[i+2],vertex_y[i+2]);
if (Math.abs(ang1-ang2) <= angle) vertex_k[i+1] = 0; }
ang1 = PointDirection(vertex_x[numPoints-2],vertex_y[numPoints-2], vertex_x[numPoints-1],vertex_y[numPoints-1]);
ang2 = PointDirection(vertex_x[numPoints-1],vertex_y[numPoints-1], vertex_x[0],vertex_y[0]);
if (Math.abs(ang1-ang2) <= angle) vertex_k[numPoints-1] = 0;
ang1 = PointDirection(vertex_x[numPoints-1],vertex_y[numPoints-1], vertex_x[0],vertex_y[0]);
ang2 = PointDirection(vertex_x[0],vertex_y[0], vertex_x[1],vertex_y[1]);
if (Math.abs(ang1-ang2) <= angle) vertex_k[0] = 0;
int n=0;for (int i=0;i<numPoints;i++)if(vertex_k[i]==1)n++;
Point[] poly= new Point[n]; n=0; for (int i=0;i<numPoints;i++) if (vertex_k[i]==1)
{ poly[n]=new Point(); poly[n].x=vertex_x[i]; poly[n].y=h-vertex_y[i];n++;} return poly;
}
double PointDirection(double xfrom,double yfrom,double xto,double yto){
return Math.atan2(yto-yfrom,xto-xfrom)*180/Math.PI ;
}

Java Convert a greyscale and sepia version of an image with BufferedImage

I want to read an image and convert and output the original image, a greyscale version, and a sepia version. I am having trouble with the conversion, not very familiar with BufferedImage, and especially having problems with getRGB and setRGB method. I have this so far
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
public class ChangeColor{
static BufferedImage readImage( String Pic ) throws Exception {
BufferedImage image = ImageIO.read( new File("Pic.jpg") );
return( image );
}
public static void saveImage( BufferedImage img, File file ) throws IOException {
ImageWriter writer = null;
java.util.Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
if( iter.hasNext() ){
writer = (ImageWriter)iter.next();
}
ImageOutputStream ios = ImageIO.createImageOutputStream( file );
writer.setOutput(ios);
ImageWriteParam param = new JPEGImageWriteParam( java.util.Locale.getDefault() );
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) ;
param.setCompressionQuality(0.98f);
writer.write(null, new IIOImage( img, null, null ), param);
}
public static BufferedImage color2gray( BufferedImage inImage ) {
int width = inImage.getWidth();
int height = inImage.getHeight();
BufferedImage outImage = new BufferedImage( width, height, BufferedImage.TYPE_3BYTE_BGR );
for(int i=0; i<height; i++){
for(int j=0; j<width; j++){
Color c = new Color(image.getRGB(j, i));
int red = (int)(c.getRed() * 0.2126);
int green = (int)(c.getGreen() * 0.7152);
int blue = (int)(c.getBlue() *0.0722);
Color newColor = new Color(red+green+blue,
red+green+blue,red+green+blue);
image.setRGB(j,i,newColor.getRGB());
}
}
return( outImage );
}
public static BufferedImage color2sepia( BufferedImage inImage ) {
int width = inImage.getWidth();
int height = inImage.getHeight();
BufferedImage outImage = new BufferedImage( width, height, BufferedImage.TYPE_3BYTE_BGR );
for(int i=0; i<height; i++){
for(int j=0; j<width; j++){
Color c = new Color(image.getRGB(j, i));
int red = (int)(c.getRed());
int green = (int)(c.getGreen());
int blue = (int)(c.getBlue());
Color newColor = new Color(red* .393)+(green*.769)+(blue* .189),
(red* .349)+(green*.686)+(blue* .168),(red* .272)+(green*.534)+(blue* .131);
image.setRGB(j,i,newColor.getRGB());
}
}
return( outImage );
}
public static void main(String[] args) throws Exception {
BufferedImage colorImage, grayImage, sepiaImage;
if (args.length != 1)
System.out.println( "" );
else
{
colorImage = readImage ( args[0] );
grayImage = color2gray ( colorImage );
sepiaImage = color2sepia( colorImage );
saveImage( grayImage, new File( "greyPic.jpg" + args[0] ) );
saveImage( sepiaImage, new File( "sepiaPic.jpg"+ args[0] ) );
}
}
}
This is an image of what the output should look like:
Thank you.
Gray scaling is rather easy, sepia not so much. I stole the algorithm off the net...
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ColorAlteration {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
BufferedImage master = ImageIO.read(new File("C:\\hold\\thumbnails\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
BufferedImage gray = toGrayScale(master);
BufferedImage sepia = toSepia(master, 80);
JPanel panel = new JPanel(new GridBagLayout());
panel.add(new JLabel(new ImageIcon(master)));
panel.add(new JLabel(new ImageIcon(gray)));
panel.add(new JLabel(new ImageIcon(sepia)));
JOptionPane.showMessageDialog(null, panel);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public static BufferedImage toGrayScale(BufferedImage master) {
BufferedImage gray = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
// Automatic converstion....
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
op.filter(master, gray);
return gray;
}
public static BufferedImage toSepia(BufferedImage img, int sepiaIntensity) {
BufferedImage sepia = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
// Play around with this. 20 works well and was recommended
// by another developer. 0 produces black/white image
int sepiaDepth = 20;
int w = img.getWidth();
int h = img.getHeight();
WritableRaster raster = sepia.getRaster();
// We need 3 integers (for R,G,B color values) per pixel.
int[] pixels = new int[w * h * 3];
img.getRaster().getPixels(0, 0, w, h, pixels);
// Process 3 ints at a time for each pixel. Each pixel has 3 RGB
// colors in array
for (int i = 0; i < pixels.length; i += 3) {
int r = pixels[i];
int g = pixels[i + 1];
int b = pixels[i + 2];
int gry = (r + g + b) / 3;
r = g = b = gry;
r = r + (sepiaDepth * 2);
g = g + sepiaDepth;
if (r > 255) {
r = 255;
}
if (g > 255) {
g = 255;
}
if (b > 255) {
b = 255;
}
// Darken blue color to increase sepia effect
b -= sepiaIntensity;
// normalize if out of bounds
if (b < 0) {
b = 0;
}
if (b > 255) {
b = 255;
}
pixels[i] = r;
pixels[i + 1] = g;
pixels[i + 2] = b;
}
raster.setPixels(0, 0, w, h, pixels);
return sepia;
}
}
You can find the original posting for the sepia algorithm here
And because I'm stubborn...I changed the sepia algorithm to work with alpha based images...
public static BufferedImage toSepia(BufferedImage img, int sepiaIntensity) {
BufferedImage sepia = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
// Play around with this. 20 works well and was recommended
// by another developer. 0 produces black/white image
int sepiaDepth = 20;
int w = img.getWidth();
int h = img.getHeight();
WritableRaster raster = sepia.getRaster();
// We need 3 integers (for R,G,B color values) per pixel.
int[] pixels = new int[w * h * 3];
img.getRaster().getPixels(0, 0, w, h, pixels);
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
int rgb = img.getRGB(x, y);
Color color = new Color(rgb, true);
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
int gry = (r + g + b) / 3;
r = g = b = gry;
r = r + (sepiaDepth * 2);
g = g + sepiaDepth;
if (r > 255) {
r = 255;
}
if (g > 255) {
g = 255;
}
if (b > 255) {
b = 255;
}
// Darken blue color to increase sepia effect
b -= sepiaIntensity;
// normalize if out of bounds
if (b < 0) {
b = 0;
}
if (b > 255) {
b = 255;
}
color = new Color(r, g, b, color.getAlpha());
sepia.setRGB(x, y, color.getRGB());
}
}
return sepia;
}
I used ##MadProgrammer code to write this code. Which I think it is much more efficient.
Using raster data of the image instead of accessing each byte of image. Although it seems it copys the data into pixels array, it is not used in the program.
You are calling getRGB each time + getWidth() + getHeight() + getRed(), getGreen() + getBlue().
Writing colors directly into your image, I think it is a bottleneck once you write a color using setRGB, you will lose graphic processor benefits. (I read it somewhere, but can't find the link now.)
Converting the color back to Color object and getting it back using getRGB().
All I did was using bit-wise operators which it is very fast and then copied the pixel arrays once I was done working with it. Function call is expensive and I avoided them.
However, thanks for the idea, #MadProgrammer.
public static BufferedImage toSepia(BufferedImage image, int sepiaIntensity) {
int width = image.getWidth();
int height = image.getHeight();
int sepiaDepth = 20;
int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);
for (int i = 0; i < imagePixels.length; i++) {
int color = imagePixels[i];
int r = (color >> 16) & 0xff;
int g = (color >> 8) & 0xff;
int b = (color) & 0xff;
int gry = (r + g + b) / 3;
r = g = b = gry;
r = r + (sepiaDepth * 2);
g = g + sepiaDepth;
if (r > 255) {
r = 255;
}
if (g > 255) {
g = 255;
}
if (b > 255) {
b = 255;
}
// Darken blue color to increase sepia effect
b -= sepiaIntensity;
// normalize if out of bounds
if (b < 0) {
b = 0;
}
if (b > 255) {
b = 255;
}
imagePixels[i] = (color & 0xff000000) + (r << 16) + (g << 8) + b;
}
BufferedImage res = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
res.setRGB(0, 0, width, height, imagePixels, 0, width);
return res;
}
You can create a filter interface for code reuse.
FilterApp
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class FilterApp {
public static ClassLoader loader = FilterApp.class.getClassLoader();
public static String outputDir = "build";
public static void main(String[] args) {
try {
BufferedImage srcImage = loadImage("lobster.jpg");
File dir = new File(outputDir);
if (!dir.exists()) {
dir.mkdirs();
}
for (FilterType filter : FilterType.values()) {
BufferedImage filteredImage = filter.applyFilter(srcImage);
String filename = String.format("%s/lobster_%s", outputDir, filter.name().toLowerCase());
writeImage(filteredImage, filename, "jpg");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage loadImage(String filename) throws IOException {
return ImageIO.read(loader.getResourceAsStream("resources/" + filename));
}
private static void writeImage(BufferedImage image, String filename, String ext) throws IOException {
ImageIO.write(image, ext, new File(filename + '.' + ext));
}
}
FilterType
import java.awt.image.BufferedImage;
import filter.GreyscaleFilter;
import filter.ImageFilter;
import filter.InvertFilter;
import filter.SepiaFilter;
public enum FilterType {
GREYSCALE(new GreyscaleFilter()),
INVERT(new InvertFilter()),
SEPIA_10(new SepiaFilter(10));
private ImageFilter filter;
public ImageFilter getFilter() { return filter; }
public BufferedImage applyFilter(BufferedImage img) {
return this.filter.apply(img);
}
private FilterType(ImageFilter filter) {
this.filter = filter;
}
}
ImageFilter
package filter;
import java.awt.image.BufferedImage;
/** Common Interface for different filters. */
public interface ImageFilter {
public BufferedImage apply(BufferedImage img);
}
GreyscaleFilter
package filter;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
public class GreyscaleFilter implements ImageFilter {
#Override
public BufferedImage apply(BufferedImage img) {
BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
op.filter(img, result);
return result;
}
}
InvertFilter
package filter;
import java.awt.Color;
import java.awt.image.BufferedImage;
public class InvertFilter implements ImageFilter {
#Override
public BufferedImage apply(BufferedImage img) {
BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
int rgb = img.getRGB(x, y);
Color color = new Color(rgb, true);
int r = 255 - color.getRed();
int g = 255 - color.getGreen();
int b = 255 - color.getBlue();
color = new Color(r, g, b, color.getAlpha());
result.setRGB(x, y, color.getRGB());
}
}
return result;
}
}
SepiaFilter
package filter;
import java.awt.Color;
import java.awt.image.BufferedImage;
// Algorithm obtained from http://stackoverflow.com/questions/21899824
public class SepiaFilter implements ImageFilter {
private int intensity;
public void setIntensity(int intensity) { this.intensity = intensity; }
public int getIntensity() { return intensity; }
public SepiaFilter(int intensity) {
this.intensity = intensity;
}
#Override
public BufferedImage apply(BufferedImage img) {
BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
// Play around with this.
// 20 works well and was recommended by another developer.
// 0 produces black/white image
int sepiaDepth = 20;
int w = img.getWidth();
int h = img.getHeight();
// We need 3 integers (for R,G,B color values) per pixel.
int[] pixels = new int[w * h * 3];
img.getRaster().getPixels(0, 0, w, h, pixels);
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
int rgb = img.getRGB(x, y);
Color color = new Color(rgb, true);
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
int gry = (r + g + b) / 3;
r = g = b = gry;
r = r + (sepiaDepth * 2);
g = g + sepiaDepth;
if (r > 255) { r = 255; }
if (g > 255) { g = 255; }
if (b > 255) { b = 255; }
// Darken blue color to increase sepia effect
b -= this.intensity;
// normalize if out of bounds
if (b < 0) { b = 0; }
if (b > 255) { b = 255; }
color = new Color(r, g, b, color.getAlpha());
result.setRGB(x, y, color.getRGB());
}
}
return result;
}
}
Output
Source Image
Generated Images

Categories

Resources