Android 如何将图像扭曲为任何四边形?

Android 如何将图像扭曲为任何四边形?,android,image,clip,distortion,Android,Image,Clip,Distortion,你们有没有人知道,如何在任何四边形中扭曲图像? 我想实现一个图像,你可以在任何方向拉任何一个角,扭曲图像。有人知道怎么做吗?我用android写东西已经有一段时间了,但android似乎没有这个功能。我真的不想写一个新的数学库:) 您好, Can看起来像你需要的。Android SDK中有一个示例演示了如何使用它 您需要使用矩阵在画布上绘制位图。您可以很容易地创建这样的转换,它将使用方法将位图图像适配到任何四边形中。它将如下所示: matrix.setPolyToPoly( ne

你们有没有人知道,如何在任何四边形中扭曲图像? 我想实现一个图像,你可以在任何方向拉任何一个角,扭曲图像。有人知道怎么做吗?我用android写东西已经有一段时间了,但android似乎没有这个功能。我真的不想写一个新的数学库:)

您好, Can

看起来像你需要的。Android SDK中有一个示例演示了如何使用它

您需要使用
矩阵
画布
上绘制位图。您可以很容易地创建这样的转换,它将使用方法将位图图像适配到任何四边形中。它将如下所示:

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是您的四边形顶点坐标。

您的代码有问题。尽管这是正确的方法,但您已经反转了float[]参数,如Android文档中所示:

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在其关于低端设备中的计算问题的评论中所说的,您可以在矩阵转换计算之前使用一些简单易行的技术来减小源图像大小(例如,颜色深度)。这将使低端手机更容易实现这一任务。

我希望这能有所帮助。左上角、右上角除左下角和右下角外都在工作。谁能加上它。我不知道如何做底部部分。:)

public类透视视图将视图实现扩展到了TouchListener上{
私人油漆公司paintRect、paintCircle;
公共int左;
公共int TOP;
公共权利;
公共int底部;
点圆_顶部_左侧;
右上角点圆;
点圆_底_左;
点圆_底部_右侧;
拉斯蒂私人酒店;
位图图像;
Rect src,dst;
矩阵2;
布尔值isTouchCirclePoints=true;
浮动变形2=5f;
公众视角(上下文){
超级(上下文);
//TODO自动生成的构造函数存根
init();
}
公共透视图(上下文、属性集属性){
超级(上下文,attrs);
//TODO自动生成的构造函数存根
init();
}
公共透视图(上下文、属性集属性、,
int-defStyle){
超级(上下文、属性、定义样式);
//TODO自动生成的构造函数存根
init();
}
私有void init(){
this.setOnTouchListener(this);
paintRect=新油漆();
paintRect.setColor(0xffff0000);
paintRect.setAntiAlias(真);
paintRect.setDither(真);
paintRect.setStyle(Paint.Style.STROKE);
paintRect.setStrokeJoin(Paint.Join.倒角);
油漆直管固定行程盖(油漆盖对接);
paintRect.设置行程宽度(3);
paintCircle=新油漆();
paintCircle.setColor(0xff000000);
paintCircle.setAntiAlias(真);
paintCircle.setDither(真);
paintCircle.setStyle(Paint.Style.FILL_和_笔划);
画圈.设置行程连接(画圈.连接.倒角);
油漆圈.调整行程盖(油漆.盖.对接);
左=90;
TOP=40;
右=500;
底部=700;
圆圈\顶部\左侧=新点(左侧,顶部);
圆圈\顶部\右侧=新点(右侧,顶部);
圆\底部\左=新点(左,底部);
圆圈\底部\右侧=新点(右侧,底部);
image=BitmapFactory.decodeResource(getResources(),R.drawable.ai);
src=新的Rect();
dst=新的Rect();
matrix2=新矩阵();
}
@凌驾
受保护的void onDraw(画布){
//画图
src.left=左;
src.top=top;
src.right=右;
src.bottom=bottom+image.getHeight();
dst.left=圆圈_顶部_左侧.x;
dst.top=圆圈_top _LEFT.y;
dst.right=圆圈_顶部_右侧.x;
dst.bottom=圆圈_bottom_RIGHT.y;
//自由变换位图
int bw=image.getWidth();
int bh=image.getHeight();
RectF src=新的RectF(左、上、bw、bh);
RectF dst=新的RectF(圆圈左上方.x+35,圆圈左上方.y+30,圆圈右上方.x,圆圈右下方.y);
matrix2.SetRectRect(src、dst、ScaleToFit.FILL);
浮点[]分={
//来源
0, 0, 
0,bh,
bw,bh,
体重,0,
//目的地
0, 0,
0, 0, 
0, 0, 
0, 0};
matrix2.mapPoints(分数,8,分数,0,4);
int DX=100;
pts[10]=圆圈左上方。x-左;
pts[12]=右上方的圆圈。x-右;
pts[13]+=0;
pts[14]+=0;
pts[15]+=右上角圆.y-左上角圆.y;
matrix2.刚毛多形性(pts,0,pts,8,4);
画布.drawBitmap(图像,矩阵2,空);
isTouchCirclePoints=假;
//左线
画布.抽绳(圆形顶部左侧.x,圆形顶部左侧.y,圆形底部左侧.x,圆形底部左侧.y,paintRect);
//线头
画布.抽绳(圆圈左上下.x,圆圈左上下.y,圆圈右上下.x,圆圈右上下.y,paintRect);
//右线
画布.抽绳(圆形顶部右侧.x,圆形顶部右侧.y,圆形底部右侧.x,圆形底部右侧.y,paintRect);
//底线
画布.抽绳(圆形底部左.x,圆形底部左.y,圆形底部右.x,圆形底部右.y,paintRect);
//在左上角画圆圈
画布.drawCircle(圆圈左上角.x,圆圈左上角.y,10,画圈);
//在右上角画圆圈
画布.drawCircle(圆圈右上角.x,圆圈右上角.y,10,画圈);
//在左下角画圆圈
画布.drawCircle(圆圈左下角.x,圆圈左下角.y,10,画圈);
//在右下角画圆圈
画布.drawCircle(圆圈底部右侧.x,圆圈底部右侧.y,10,画圈);
}
@凌驾
公共布尔onTouch(视图、运动事件){
lastX=(int)event.getX
public class PerspectiveDistortView extends View  implements 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;
Rect src, dst;
Matrix matrix2;
boolean isTouchCirclePoints = true;
float deform2 = 5f;

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.ai);

    src = new Rect();
    dst = new Rect();

    matrix2 = new Matrix();
}

@Override
protected void onDraw(Canvas canvas) {
    // draw image
    src.left = LEFT;
    src.top = TOP;
    src.right = RIGHT;
    src.bottom = BOTTOM + image.getHeight();

    dst.left = CIRCLE_TOP_LEFT.x;
    dst.top = CIRCLE_TOP_LEFT.y;
    dst.right = CIRCLE_TOP_RIGHT.x;
    dst.bottom = CIRCLE_BOTTOM_RIGHT.y;

    // Free Transform bitmap
        int bw = image.getWidth();
        int bh = image.getHeight();
        RectF src = new RectF(LEFT, TOP, bw, bh);
        RectF dst = new RectF(CIRCLE_TOP_LEFT.x + 35, CIRCLE_TOP_LEFT.y + 30, CIRCLE_TOP_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y);
        matrix2.setRectToRect(src, dst, ScaleToFit.FILL);

        float[] pts = {
                       // source
                       0, 0, 
                       0, bh, 
                       bw, bh, 
                       bw, 0,
                       // destination
                       0, 0,
                       0, 0, 
                       0, 0, 
                       0, 0};
        matrix2.mapPoints(pts, 8, pts, 0, 4);
        int DX = 100;
        pts[10] -= CIRCLE_TOP_LEFT.x - LEFT; 
        pts[12] -= CIRCLE_TOP_RIGHT.x - RIGHT;
        pts[13] += 0;
        pts[14] += 0;
        pts[15] += CIRCLE_TOP_RIGHT.y - CIRCLE_TOP_LEFT.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;
    }
}
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;
    }
}
}