Искажение изображения в четырехугольник в некоторых случаях терпит неудачу на Android

Я использую функцию matrix.setPolyToPoly, чтобы преобразовать выбранную область (4 угла) растрового изображения в прямоугольник и, как правило, он работает потрясающе. Но в следующем примере:

4 corners selection image

Функция polyToPoly не выполняет преобразование перспективы:

Bad transformation image

Я нарисовал две строки для тестирования, строки отмечают, где я хочу четыре выбранные точки.

Что я делаю неправильно? Спасибо!

EDIT. Я решил проблему, используя canvas.drawBitmapMesh, Спасибо pskink за ваш совет!!

Это окончательный код

private float[] generateVertices(int widthBitmap, int heightBitmap) {
    float[] vertices=new float[(WIDTH_BLOCK+1)*(HEIGHT_BLOCK+1)*2];

    float widthBlock = (float)widthBitmap/WIDTH_BLOCK;
    float heightBlock = (float)heightBitmap/HEIGHT_BLOCK;

    for(int i=0;i<=HEIGHT_BLOCK;i++)
        for(int j=0;j<=WIDTH_BLOCK;j++) {
            vertices[i * ((HEIGHT_BLOCK+1)*2) + (j*2)] = j * widthBlock;
            vertices[i * ((HEIGHT_BLOCK+1)*2) + (j*2)+1] = i * heightBlock;
        }
    return vertices;
}

private Bitmap perspectiveTransformation(Bitmap bitmap, ArrayList<Point> bitmapPoints) {

    Bitmap correctedBitmap;
    int maxX = (int) Math.max(Math.abs(bitmapPoints.get(0).x - bitmapPoints.get(1).x), Math.abs(bitmapPoints.get(2).x - bitmapPoints.get(3).x));
    int maxY = (int) Math.max(Math.abs(bitmapPoints.get(0).y - bitmapPoints.get(3).y), Math.abs(bitmapPoints.get(1).y - bitmapPoints.get(2).y));
    Log.d("max", "x=" + maxX + " y=" + maxY); //This is the desired final size

    Bitmap.Config conf = Bitmap.Config.ARGB_8888;
    correctedBitmap = Bitmap.createBitmap(maxX,maxY,conf); //the final bitmap
    float mVertices[] =generateVertices(bitmap.getWidth(),bitmap.getHeight());

    Point mLeftTop = bitmapPoints.get(0);
    Point mRightTop = bitmapPoints.get(1);
    Point mLeftBot = bitmapPoints.get(3);
    Point mRightBot = bitmapPoints.get(2);  //the points on the image where the user has clicked

    Canvas canvas = new Canvas(correctedBitmap);

    Matrix matrix = new Matrix();
    matrix.setPolyToPoly(
            new float[]{mLeftTop.x, mLeftTop.y,
                    mRightTop.x, mRightTop.y,
                    mRightBot.x, mRightBot.y,
                    mLeftBot.x, mLeftBot.y   //the user points
            },
            0,
            new float[]{0, 0,
                    maxX - 1, 0,
                    maxX - 1, maxY - 1,
                    0, maxY - 1             //where I want the user points in the corrected image
            }
            , 0, 4);

    canvas.concat(matrix);

    Paint paint = new Paint();
    paint.setAntiAlias(true);       //testing parameters
    paint.setFilterBitmap(true);    //testing parameters

    paint.setColor(Color.BLUE);
    paint.setStyle(Paint.Style.STROKE);

    canvas.drawBitmapMesh(bitmap, WIDTH_BLOCK , HEIGHT_BLOCK, mVertices,0,null,0, paint);  //draw the original bitmap into the corrected bitmap with PolyToPoly transformation matrix

    canvas.drawLine(mLeftTop.x, mLeftTop.y, mRightBot.x, mRightBot.y, paint); //draw two lines for testing the transformation matrix
    canvas.drawLine(mLeftBot.x, mLeftBot.y, mRightTop.x, mRightTop.y, paint);

    //bitmap.recycle();  //just testing

    return correctedBitmap;
}

Ответ 1

private float[] generateVertices(int widthBitmap, int heightBitmap) {
    float[] vertices=new float[(WIDTH_BLOCK+1)*(HEIGHT_BLOCK+1)*2];

    float widthBlock = (float)widthBitmap/WIDTH_BLOCK;
    float heightBlock = (float)heightBitmap/HEIGHT_BLOCK;

    for(int i=0;i<=HEIGHT_BLOCK;i++)
        for(int j=0;j<=WIDTH_BLOCK;j++) {
            vertices[i * ((HEIGHT_BLOCK+1)*2) + (j*2)] = j * widthBlock;
            vertices[i * ((HEIGHT_BLOCK+1)*2) + (j*2)+1] = i * heightBlock;
        }
    return vertices;
}

private Bitmap perspectiveTransformation(Bitmap bitmap, ArrayList<Point> bitmapPoints) {

    Bitmap correctedBitmap;
    int maxX = (int) Math.max(Math.abs(bitmapPoints.get(0).x - bitmapPoints.get(1).x), Math.abs(bitmapPoints.get(2).x - bitmapPoints.get(3).x));
    int maxY = (int) Math.max(Math.abs(bitmapPoints.get(0).y - bitmapPoints.get(3).y), Math.abs(bitmapPoints.get(1).y - bitmapPoints.get(2).y));
    Log.d("max", "x=" + maxX + " y=" + maxY); //This is the desired final size

    Bitmap.Config conf = Bitmap.Config.ARGB_8888;
    correctedBitmap = Bitmap.createBitmap(maxX,maxY,conf); //the final bitmap
    float mVertices[] =generateVertices(bitmap.getWidth(),bitmap.getHeight());

    Point mLeftTop = bitmapPoints.get(0);
    Point mRightTop = bitmapPoints.get(1);
    Point mLeftBot = bitmapPoints.get(3);
    Point mRightBot = bitmapPoints.get(2);  //the points on the image where the user has clicked

    Canvas canvas = new Canvas(correctedBitmap);

    Matrix matrix = new Matrix();
    matrix.setPolyToPoly(
            new float[]{mLeftTop.x, mLeftTop.y,
                    mRightTop.x, mRightTop.y,
                    mRightBot.x, mRightBot.y,
                    mLeftBot.x, mLeftBot.y   //the user points
            },
            0,
            new float[]{0, 0,
                    maxX - 1, 0,
                    maxX - 1, maxY - 1,
                    0, maxY - 1             //where I want the user points in the corrected image
            }
            , 0, 4);

    canvas.concat(matrix);

    Paint paint = new Paint();
    paint.setAntiAlias(true);       //testing parameters
    paint.setFilterBitmap(true);    //testing parameters

    paint.setColor(Color.BLUE);
    paint.setStyle(Paint.Style.STROKE);

    canvas.drawBitmapMesh(bitmap, WIDTH_BLOCK , HEIGHT_BLOCK, mVertices,0,null,0, paint);  //draw the original bitmap into the corrected bitmap with PolyToPoly transformation matrix

    canvas.drawLine(mLeftTop.x, mLeftTop.y, mRightBot.x, mRightBot.y, paint); //draw two lines for testing the transformation matrix
    canvas.drawLine(mLeftBot.x, mLeftBot.y, mRightTop.x, mRightTop.y, paint);

    //bitmap.recycle();  //just testing

    return correctedBitmap;
}