在Android上裁剪图像的透视转换

Mat*_*ade 11 android image transform bitmap matrix

我正在尝试对通过相机捕获的位图进行透视变换.用户围绕矩形对象调整边界四边形(如白框所示).然后,我尝试使用以下代码将其转换为矩形图像:

public static Bitmap perspectiveTransformation(Bitmap bitmap,BoundingQuad boundingQuad)
{
    Matrix matrix = new Matrix();
    float[] dst = new float[] {
            0,
            0,
            bitmap.getWidth(),
            0,
            bitmap.getWidth(),
            bitmap.getHeight(),
            0,
            bitmap.getHeight()
    };
    float[] src = new float[] {
            boundingQuad.topLeft.x,
            boundingQuad.topLeft.y,
            boundingQuad.topRight.x,
            boundingQuad.topRight.y,
            boundingQuad.bottomRight.x,
            boundingQuad.bottomRight.y,
            boundingQuad.bottomLeft.x,
            boundingQuad.bottomLeft.y
    };
    matrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
Run Code Online (Sandbox Code Playgroud)

但是,我生成的图像包含超出我的四边形边界的图像数据.如果我可以弄清楚变换后四边形的坐标是什么,这是可以接受的,所以我可以裁剪结果,但我完全不知道如何做到这一点.

在转换后找到四边形的坐标或理想地找到防止这种情况首先发生的方法时,将非常感谢任何帮助.

输入:

http://i.stack.imgur.com/33RfN.png

输出:

http://i.stack.imgur.com/zWFvA.png

小智 6

我遇到了同样的问题,并通过在转换后找到矩形的坐标来解决它.

要找到这些坐标,您必须了解发生了什么.矩阵定义了透视变换,其由四边形的4个边缘点和对应点给出.您已使用以下代码完成此操作:

Matrix matrix = new Matrix();
float[] dst = new float[] {
        0,
        0,
        bitmap.getWidth(),
        0,
        bitmap.getWidth(),
        bitmap.getHeight(),
        0,
        bitmap.getHeight()
};
float[] src = new float[] {
        boundingQuad.topLeft.x,
        boundingQuad.topLeft.y,
        boundingQuad.topRight.x,
        boundingQuad.topRight.y,
        boundingQuad.bottomRight.x,
        boundingQuad.bottomRight.y,
        boundingQuad.bottomLeft.x,
        boundingQuad.bottomLeft.y
}; 
matrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);
Run Code Online (Sandbox Code Playgroud)

这意味着(例如)四边形的左上角转换为点(0,0).您可以通过将矩阵应用于点并检查结果值来验证这一点.要应用矩阵,您可以使用该方法mapPoints(...).定义的转换矩阵工作正常.这个转换的奇怪行为(初看起来)来自于位图的创建:

    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
Run Code Online (Sandbox Code Playgroud)

生成的位图似乎是错误的,因为一些点(例如四边形左上角的所有点)都被转换为负坐标,如果要将某些内容绘制到位图中,则坐标必须为正.因此,变换点是移位的,并且导致位图中变换点的奇怪坐标.

总结:点被正确地转换为新坐标,但是不能显示,因此它们被移位并且位图中变换点的移位坐标不是在变换矩阵中定义的坐标.

要解决此问题并获取位图中转换点的正确坐标,您必须计算移位的值.移位由x值和y值组成.

为了计算x值,我使用先前定义的矩阵将原始图像的左上点的x值和左下点的x值变换.左上角点或左下角点被转换为结果位图的左边界,因此此点的位图坐标的x值等于0且否定(因为x-值必须是正的)变换坐标的x值是移位的x值.转换为结果位图左边界的点是具有最大否定x值的点.因此,移位的x值是变换的左上和左下点的否定x值的最大值.

为了计算y值,我转换了左上角的y值和原始图像的右上角的y值,因为这是转换到结果的顶部边界的可能点.位图和变换点的y值在结果位图中等于0.通过再次获取变换的y值的否定值的最大值,可以得到移位的y值.

生成的代码如下所示:

    float[] mappedTL = new float[] { 0, 0 };
    matrix.mapPoints(mappedTL);
    int maptlx = Math.round(mappedTL[0]);
    int maptly = Math.round(mappedTL[1]);

    float[] mappedTR = new float[] { bitmap.getWidth(), 0 };
    matrix.mapPoints(mappedTR);
    int maptrx = Math.round(mappedTR[0]);
    int maptry = Math.round(mappedTR[1]);

    float[] mappedLL = new float[] { 0, bitmap.getHeight() };
    matrix.mapPoints(mappedLL);
    int mapllx = Math.round(mappedLL[0]);
    int maplly = Math.round(mappedLL[1]);

    int shiftX = Math.max(-maptlx, -mapllx);
    int shiftY = Math.max(-maptry, -maptly);

    Bitmap resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    return Bitmap.createBitmap(resultBitmap, shiftX, shiftY, bitmap.getWidth(), bitmap.getHeight(), null, true);
Run Code Online (Sandbox Code Playgroud)


Has*_*aan -3

创建新Bitmap图像后,您可以通过构建“裁剪”意图并调用它来调用 Android 的内置裁剪功能,例如:

Intent cropIntent = new Intent("com.android.camera.action.CROP");

// Put in 'Extras' here to build the intent

// Start the activity. It will be handled by returning data to onActivityResult
startActivityForResult(cropIntent, PIC_CROP); // PIC_CROP is just an arbitrary tag name.
Run Code Online (Sandbox Code Playgroud)

有关 Android 中图像裁剪的更多详细信息,请访问此处

您还需要在应用程序的清单文件中添加以下内容才能使其正常工作:

<uses-feature android:name="android.hardware.camera" ></uses-feature>
<uses-permission android:name="android.permission.CAMERA" />
Run Code Online (Sandbox Code Playgroud)