android - 在 Android 上裁剪图像的透视变换

标签 android image matrix bitmap transform

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

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 个边缘点和相应的点给出。您已使用以下代码完成此操作:

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 值和转换点的 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);

关于android - 在 Android 上裁剪图像的透视变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13161628/

相关文章:

android - 将字符串保存到内部存储器然后显示它

html - 额外的 div 导致图像高度无法正确缩放(显示 : flex)

javascript - Javascript 中的矩阵对象和矩阵旋转函数

android - 如何在 Android 中检索 ParseObject 的所有行

android - 使用 Sonarqube 分析 Android Studio (Gradle) 项目

python - 遍历文件夹树并将 xmp 数据添加到文件夹中的文件,然后移动

c++ - 在 C++ 中为多维特征矩阵赋值?

c++ - 二维矩阵的推送和弹出操作并在 C++ 中显示它们

android - 如何在 React Native 0.60-RC 中生成签名的 apk

html - 使文本在响应图像中保持在同一位置