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/

相关文章:

java - Android中的合理文本布局?

android - 设置 imageView 更小与缩放图像本身之间的区别

java - java - 如何检查给定图像是否是Java中的CMYK?

c# - 如何从矩阵中获取一维数组

android - Android 中的库可以有自己的 Intent 过滤器吗?

android - 不正确的用户界面 - 安卓

javascript - 虚拟键盘缩放网页

javascript - 一些通过 Webpack 文件加载器加载的图片没有找到

c++ - 在测量代码的运行时间时,我将如何使用执行代码来求解矩阵?

java - Java稀疏矩阵创建