5

ゲームをプログラミングしていて、透明な境界線 (スプライト) を持つ画像を円に対して衝突させたいと考えています。

透明でないピクセルとの衝突をチェックすることで、円が画像に重なっているかどうかを簡単に知ることができます。

私が抱えている問題は、バウンスを行うための通常の角度を知ることです。

画像を指定すると、画像の境界にあるピクセルを含む配列を返すライブラリ(Java)またはアルゴリズムが必要になるため、サーフェスの2点間の勾配を見つけることができます。

学習できるライブラリ/アルゴリズム/コード スニペットはありますか?

4

2 に答える 2

9

簡単なアプローチは次のとおりです。

0すべての透明ピクセルがあり、すべての非透明ピクセルがある元の画像からマスクを作成します。1

次に、ピクセルからまたは(x,y)となる各ピクセル を減算し、絶対値を取得することにより、マスクで単純なエッジ検出を実行します。01(x+1,y+1)

これ1により、画像の端のピクセルとそれ以外のすべてのピクセルが得られます0

注: この方法は、基本的に画像を 2d 関数として扱い、その勾配を計算することと同じです。エッジは、強度面の急峻な部分です (大きな勾配値に対応します)。勾配ベースのエッジ検出に関する詳細情報は次のとおりです。


画像の例を次に示します。

元のテスト画像

最初にすべての非透明ピクセルをマスクします。

画像マスク

次に、画像を 1 ピクセル分下にシフトし、画像自体から減算します。

これにより、下の画像が作成されます。ここで、単純に 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 に答える