5

我正在编写游戏,我想将带有透明边框(精灵)的图像与圆形碰撞。

通过检查与不透明像素的碰撞,很容易知道圆圈是否与图像重叠。

我遇到的问题是要知道法线角度以便反弹。

我需要一个库(Java)或算法,给定一个图像,它将返回一个数组,其中包含图像边界处的像素,这样我就可以找到表面两点之间的斜率。

有没有我可以学习的库/算法/代码片段?

4

2 回答 2

9

这是一个简单的方法:

0从所有透明像素和所有非透明像素的原始图像创建蒙版1

(x,y)然后,通过从像素中减去每个像素(即01(x+1,y+1)并取绝对值,对您的蒙版执行简单的边缘检测。

这将为您1提供图像边缘的像素和0其他任何地方的像素。

注意:这种方法本质上等同于将图像视为二维函数并计算其梯度。边缘是强度表面的陡峭部分(对应于大梯度值)。这是有关基于梯度的边缘检测的更多信息。


这是一个示例图像:

原始测试图像

首先屏蔽所有不透明的像素:

图像蒙版

然后将图像向下移动一个像素,然后将其从自身中减去。

这将创建下面的图像。现在只需用 value 读出矩阵索引1

那是你的边缘像素数组。

边缘蒙版

注意:如果您的图像包含内部透明像素,此技术也会发现内部边缘,这对您来说可能是也可能不是问题......

于 2012-04-21T14:33:33.737 回答
3

这是我长期以来实施的:(detectionStrength 最好 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;
}

还有 Pixel 类(只是一个非常简单的扩展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 + "]";
    }
}

使用该算法创建的图像将是:

StackOverflow 徽标

于 2013-02-22T09:18:37.817 回答