14

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

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);
}

但是,我生成的图像包含在我的四边形边界之外的图像数据。如果我能弄清楚变换后四边形的坐标是什么,这将是可以接受的,这样我就可以裁剪结果,但我完全不知道该怎么做。

无论是在转换后找到四边形的坐标,还是理想地找到一种方法来防止这种情况首先发生,任何帮助都将不胜感激。

输入:

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

输出:

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

4

2 回答 2

9

我有同样的问题,并通过在变换后找到矩形的坐标来解决它。

要找到这些坐标,您必须了解发生了什么。该矩阵定义了一个透视变换,由四边形的 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);

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

    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

生成的位图似乎是错误的,因为某些点(例如四边形左上角左侧的所有点)都转换为负坐标,如果您想将某些东西绘制到位图中,坐标必须为正. 因此,变换点是移位的,这会导致位图中变换点的奇怪坐标。

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

为了解决这个问题并获得位图中变换点的正确坐标,您必须计算移位的值。位移由一个 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);
于 2014-10-30T12:30:41.430 回答
-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.

可以从这里获得有关 Android 中图像裁剪的更多详细信息。

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

<uses-feature android:name="android.hardware.camera" ></uses-feature>
<uses-permission android:name="android.permission.CAMERA" />
于 2013-10-25T16:36:30.777 回答