图像/graphics成形
我想知道是否有任何方法将图像/graphics转换成Shape
? 例如,我可以将摩托车形状的轮廓转换成一个Shape
所以我可以在Java中使用它? 我知道你可以用正方形或圆angular,多边形等来做到这一点。但有没有办法做一个自定义形状?
motorcycle.jpg
摩托车03.png
ImageOutline.java
此代码需要一定的耐心(运行时)。
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"); } }
函数getArea_FastHack
build立在Andrew Thompsons的工作上,这非常有帮助。 矿山应该更快,但是:(/ /编辑:和sloppier也是)
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(); } } }
这是更快,但不太准确,有用的碰撞检查或2D物理。
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 ; }