9

四角形で画像を歪める方法を知っている人はいますか? 画像を歪ませて、任意のコーナーを任意の方向に引っ張ることができる画像を実装したいと思います。誰でもそれを行う方法を知っていますか? 私はしばらくアンドロイドで何かを使ったり書いたりしていますが、アンドロイドにはそのための機能があるようには見えません。新しい数学ライブラリを書く気がしません:)。

こんにちは、カン

4

5 に答える 5

9

Canvas.drawBitmapMeshが必要なようです。Android SDK には、その使用方法を示すサンプルがあります。

Matrixにビットマップを描画するために使用する必要がありますCanvasMatrix.polyToPolyメソッドを使用して、ビットマップ画像を任意の四角形に適合させるような変換を簡単に作成できます。次のようになります。

matrix.setPolyToPoly(
        new float[] { 
            0, 0, 
            bitmap.getWidth(), 0
            0, bitmap.getHeight(),
            bitmap.getWidth(), bitmap.getHeight() 
        }, 0, 
        new float[] { 
            x0, y0, 
            x1, y1, 
            x2, y2,
            x3, y3
        }, 0, 
        4);

canvas.drawBitmap(bitmap, matrix, paint);

x0-x3、y0-y3 は四角形の頂点座標です。

于 2012-12-18T15:17:20.427 に答える
4

@donmj。コードを修正しました。

public class PerspectiveDistortView extends View implements View.OnTouchListener {

private Paint paintRect, paintCircle;
public int LEFT;
public int TOP;
public int RIGHT;
public int BOTTOM;
Point CIRCLE_TOP_LEFT;
Point CIRCLE_TOP_RIGHT;
Point CIRCLE_BOTTOM_LEFT;
Point CIRCLE_BOTTOM_RIGHT;
private int lastX, lastY;
Bitmap image;
Matrix matrix2;
boolean isTouchCirclePoints = true;

public PerspectiveDistortView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
    init();
}

public PerspectiveDistortView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
    init();
}

public PerspectiveDistortView(Context context, AttributeSet attrs,
                              int defStyle) {
    super(context, attrs, defStyle);
    // TODO Auto-generated constructor stub
    init();
}

private void init() {
    this.setOnTouchListener(this);
    paintRect = new Paint();
    paintRect.setColor(0xffff0000);
    paintRect.setAntiAlias(true);
    paintRect.setDither(true);
    paintRect.setStyle(Paint.Style.STROKE);
    paintRect.setStrokeJoin(Paint.Join.BEVEL);
    paintRect.setStrokeCap(Paint.Cap.BUTT);
    paintRect.setStrokeWidth(3);
    paintCircle = new Paint();
    paintCircle.setColor(0xff000000);
    paintCircle.setAntiAlias(true);
    paintCircle.setDither(true);
    paintCircle.setStyle(Paint.Style.FILL_AND_STROKE);
    paintCircle.setStrokeJoin(Paint.Join.BEVEL);
    paintCircle.setStrokeCap(Paint.Cap.BUTT);

    LEFT = 90;
    TOP = 40;
    RIGHT = 500;
    BOTTOM = 700;
    CIRCLE_TOP_LEFT = new Point(LEFT, TOP);
    CIRCLE_TOP_RIGHT = new Point(RIGHT, TOP);
    CIRCLE_BOTTOM_LEFT = new Point(LEFT, BOTTOM);
    CIRCLE_BOTTOM_RIGHT = new Point(RIGHT, BOTTOM);

    image = BitmapFactory.decodeResource(getResources(), R.drawable.penguins);

    matrix2 = new Matrix();
}

@Override
protected void onDraw(Canvas canvas) {
    // Free Transform bitmap
    int bw = image.getWidth();
    int bh = image.getHeight();

    float[] pts = {
            // source
            0, 0,
            0, bh,
            bw, bh,
            bw, 0,
            // destination
            0, 0,
            0, 0,
            0, 0,
            0, 0};
    pts[8] = CIRCLE_TOP_LEFT.x;
    pts[9] = CIRCLE_TOP_LEFT.y;
    pts[10] = CIRCLE_BOTTOM_LEFT.x;
    pts[11] = CIRCLE_BOTTOM_LEFT.y;
    pts[12] = CIRCLE_BOTTOM_RIGHT.x;
    pts[13] = CIRCLE_BOTTOM_RIGHT.y;
    pts[14] = CIRCLE_TOP_RIGHT.x;
    pts[15] = CIRCLE_TOP_RIGHT.y;

    matrix2.setPolyToPoly(pts, 0, pts, 8, 4);
    canvas.drawBitmap(image, matrix2, null);
    isTouchCirclePoints = false;

    // line left
    canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, paintRect);
    // line top
    canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, paintRect);
    // line right
    canvas.drawLine(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect);
    // line bottom
    canvas.drawLine(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect);
    // circle top left
    canvas.drawCircle(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 10, paintCircle);
    // circle top right
    canvas.drawCircle(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 10, paintCircle);
    // circle bottom left
    canvas.drawCircle(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 10, paintCircle);
    // circle bottom right
    canvas.drawCircle(CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 10, paintCircle);
}

@Override
public boolean onTouch(View view, MotionEvent event) {
    lastX = (int) event.getX();
    lastY = (int) event.getY();

    if (inCircle(lastX, lastY, CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 40)) {
        isTouchCirclePoints = true;
        CIRCLE_TOP_LEFT.set(lastX, lastY);
    } else if (inCircle(lastX, lastY, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 40)) {
        isTouchCirclePoints = true;
        CIRCLE_TOP_RIGHT.set(lastX, lastY);
    } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 40)) {
        isTouchCirclePoints = true;
        CIRCLE_BOTTOM_LEFT.set(lastX, lastY);
    } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 40)) {
        isTouchCirclePoints = true;
        CIRCLE_BOTTOM_RIGHT.set(lastX, lastY);
    }
    invalidate();
    return true;
}

private boolean inCircle(float x, float y, float circleCenterX, float circleCenterY, float circleRadius) {
    double dx = Math.pow(x - circleCenterX, 2);
    double dy = Math.pow(y - circleCenterY, 2);

    if ((dx + dy) < Math.pow(circleRadius, 2)) {
        return true;
    } else {
        return false;
    }
}
}
于 2016-01-07T23:23:58.720 に答える
3

コードに問題があります。これは正しい方法ですが、Android のドキュメントに示されているように、float[] パラメータを逆にしています。

public boolean setPolyToPoly (float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)
WHERE
src: The array of src [x,y] pairs (points)
...
dst: The array of dst [x,y] pairs (points)

したがって、コードに従って、マトリックスは次のように作成する必要があります。

matrix.setPolyToPoly(
        new float[] {
            x0, y0,
            x1, y1,
            x2, y2,
            x3, y3},
    0,
new float[] { 
        0, 0, 
        bitmap.getWidth(), 0
        0, bitmap.getHeight(),
        bitmap.getWidth(), bitmap.getHeight() 
    }, 0, 
    4);

このようにして、アプリは画像に示すように正常に動作します。

ここに画像の説明を入力

一方、ローエンド デバイスの計算上の問題についての user2498079 のコメントについては、マトリックス変換計算の前に、いくつかの簡単な手法を使用してソース イメージのサイズ (および色深度など) を小さくすることができます。 . ローエンドの電話がこのタスクを実現しやすくなります。

于 2015-09-30T16:26:56.663 に答える