2012-04-21 30 views
5

Estoy programando un juego y quiero colidar las imágenes con bordes transparentes (sprites) agnist un círculo.Encontrar los píxeles del borde de una imagen con un entorno transparente (para detección de colisión)

Es fácil saber si el círculo se superpone a la imagen al verificar la colisión con los píxeles que no son transparentes.

El problema que tengo es conocer el ángulo normal para hacer un rebote.

Necesitaría una biblioteca (Java) o algoritmo que da una imagen que devolvería una matriz con los píxeles que están en el borde de la imagen para que pueda encontrar la pendiente entre dos puntos de la superficie.

¿Hay alguna biblioteca/algoritmo/fragmento de código que pueda aprender?

Muchas gracias

Lau.

Respuesta

8

Aquí es un enfoque simple:

Crear una máscara a partir de la imagen original en el que todos los píxeles transparentes son 0 y todos los píxeles no transparentes están 1

A continuación, realice un simple detección de bordes en su máscara restando cada píxel (x,y), que será 0 o 1, a partir del píxel (x+1,y+1) y tomando el valor absoluto.

Esto le dará un 1 para píxeles en el borde de la imagen y un 0 en cualquier otro lugar.

Nota: este método es esencialmente equivalente a tratar la imagen como una función 2d y calcular su gradiente. Los bordes son empinado partes de la superficie de intensidad (que corresponden a los valores de gradiente grande). Aquí hay más información sobre gradient-based edge detection.


Aquí es una imagen de ejemplo:

Original Test Image

primera máscara de todos los píxeles no transparentes:

Image Mask

después desplazar la imagen hacia abajo y más de un píxel y restar de sí mismo.

Esto crea la imagen a continuación. Ahora simplemente lea los índices de la matriz con el valor 1.

Esa es su matriz de píxeles de borde.

Edge Mask

Nota: si las imágenes contienen interiores píxeles transparentes, esta técnica también encontrará bordes interiores, que pueden o no ser un problema para usted ...

3

Esto es lo que Me'v realizarán a lo largo del tiempo: (detectionStrength es mejor 10)

public static List<Pixel> getEdges(Image image, int detectionStrength) { 

    boolean[][] opaque = new boolean[image.getWidth(null)][image 
      .getHeight(null)]; 
    LinkedList<Pixel> edges = new LinkedList<Pixel>(); 
    int rgb; 

    /* 
    * convert to BufferedImage to get individual pixel colors 
    */ 
    BufferedImage bufferedImage; 
    if (image instanceof BufferedImage) 
     bufferedImage = (BufferedImage) image; 
    else { 
     bufferedImage = new BufferedImage(image.getWidth(null), 
       image.getHeight(null), BufferedImage.TYPE_INT_ARGB); 
     bufferedImage.createGraphics().drawImage(image, 0, 0, null); 
    } 

    for (int i = 0; i < opaque.length; i++) { 
     for (int j = 0; j < opaque[i].length; j++) { 
      rgb = bufferedImage.getRGB(i, j); 
      opaque[i][j] = (rgb >> 24 & 0xFF) > detectionStrength; // transparency 
     } 
    } 

    /* 
    * If a pixel is opaque, but is surrounded, with at least one 
    * transparent pixel, it is considered an edge. 
    */ 
    for (int x = 0; x < opaque.length; x++) { 
     for (int y = 0; y < opaque[x].length; y++) { 
      if ((x == 0) || (x == opaque.length - 1) || (y == 0) 
        || (y == opaque[x].length - 1)) { // border pixel 
       if (opaque[x][y]) // if opaque, it is automatically an edge, 
            // no matter its surrounding... 
        edges.add(new Pixel(x, y, new Color(bufferedImage 
          .getRGB(x, y)))); 

      } else { // not a border pixel 
       if (opaque[x][y] 
         && (!opaque[x - 1][y - 1] || !opaque[x][y - 1] 
           || !opaque[x + 1][y - 1] 
           || !opaque[x - 1][y] || !opaque[x + 1][y] 
           || !opaque[x - 1][y + 1] 
           || !opaque[x][y + 1] || !opaque[x + 1][y + 1])) 
        edges.add(new Pixel(x, y, new Color(bufferedImage 
          .getRGB(x, y)))); 
      } 
     } 
    } 

    return edges; 
} 

Y la clase de píxeles (sólo una extensión muy simple de Point):

public class Pixel extends Point implements Cloneable { 

    private static final long serialVersionUID = -9053911985748552077L; 

    public Color color; 

    public Pixel(int x, int y, Color c) { 
     super(x, y); 
     color = c; 
    } 

    public Pixel(Pixel other) { 
     super(other.x, other.y); 
     color = other.color; 
    } 

    public Color getColor() { 
     return color; 
    } 

    public void setColor(Color newColor) { 
     color = newColor; 
    } 

    public int hashCode() { 
     final int prime = 31; 
     int result = super.hashCode(); 
     result = prime * result + ((color == null) ? 0 : color.hashCode()); 
     return result; 
    } 

    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (!super.equals(obj)) 
      return false; 
     if (!(obj instanceof Pixel)) 
      return false; 
     Pixel other = (Pixel) obj; 
     if (color == null) { 
      if (other.color != null) 
       return false; 
     } else if (!color.equals(other.color)) 
      return false; 
     return true; 
    } 

    public Object clone() { 
     return new Pixel(x, y, color); 
    } 

    public String toString() { 
     return "Pixel [color=" + color + ", x=" + x + ", y=" + y + "]"; 
    } 
} 

El imagen creada con el algoritmo, será:

StackOverflow logo

Cuestiones relacionadas