从点的角度对UIImage进行透视校正

15
我正在开发一款应用程序,用户可以拍摄名片或照片。然后,用户将标记物体的四个角落(他们拍摄的物体),就像在许多文档/图像/名片扫描应用程序中看到的那样:

enter image description here

我的问题是如何根据这四个点裁剪和修复透视?我已经搜索了几天,并查看了几个图像处理库,但没有找到合适的解决方案。有谁能指点我一下方向吗?

以下是另一种实现方法:https://dev59.com/mWox5IYBdhLWcg3wDgEz。如果有帮助,请告诉我。 - MonsieurDart
你好,你解决了吗?能否把这个问题的代码发一下?我需要和这个一模一样的。 - Mani
@mani,我从未找到一个好的解决方案。很遗憾。 - Jakob Halskov
4个回答

9

从iOS8+开始,有一个名为CIPerspectiveCorrection的核心图像滤镜。您所需要做的就是传递图像和四个点。Perspective Correction

此外,还有一个支持iOS6+的滤镜称为CIPerspectiveTransform,可以用类似的方式(扭曲图像)。


感谢您让我意识到这个问题 :) - Jakob Halskov

1
如果将此图像作为纹理加载,使用OpenGL进行扭曲将非常简单。您只需绘制一个全屏四边形,并在每个点处使用黄色校正点作为UV坐标即可。

2
矩形上的纹理将会被扭曲,因此会看到对角线。为了正确地映射“透视”矩形,我们需要处理纹理的z坐标。 - brigadir
在这种浅角度下,我不认为这会有太大的影响。但如果正确性非常重要,使用OpenGL仍然很容易。只需将图像绘制为四边形(这次保留UV坐标),但不是将相机正对着它,而是稍微调整相机位置以补偿原始图片的倾斜。现在唯一的挑战是确定相机放置的位置。 - StilesCrisis
那种解决方案唯一的问题是,任何想要进行透视校正的人都希望将图像保存在完整的原始分辨率下(或尽可能接近于由控制点放置所产生的自然裁剪)。因此,在这种情况下,您可以在屏幕上很好地显示透视校正后的图像,但是否可能将其保存到磁盘上呢? - Joel Martinez
谢谢您的建议 - 这听起来是一个好的解决方案!我的问题现在是如何“做”和实现这个。我对OpenGL ES有基本的了解,但我不确定如何将图像绘制为四边形。 - Jakob Halskov
绘制四边形是您可以执行的最简单的操作之一。您只需使用两个三角形绘制一个平面矩形即可。 - StilesCrisis

1
我不确定你是否尝试过Opencv库,但它有一种非常好的方式来去除图像的扭曲。我这里有一个小片段,它需要一个角点数组(例如你的四个角点)和最终映射到的大小。
你可以阅读warpPerspective的手册,在OpenCV网站上查看。
cv::Mat deskew(cv::Mat& capturedFrame, cv::Point2f source_points[], cv::Size finalSize)
{
    cv::Point2f dest_points[4];

    // Output of deskew operation has same color space as source frame, but
    // is proportional to the area the document occupied; this is to reduce
    // blur effects from a scaling component.
    cv::Mat deskewedMat = cv::Mat(finalSize, capturedFrame.type());

    cv::Size s = capturedFrame.size();

    // Deskew to full output image corners
    dest_points[0] = cv::Point2f(0,s.height); // lower left
    dest_points[1] = cv::Point2f(0,0);        // upper left
    dest_points[2] = cv::Point2f(s.width,0);  // upper right
    dest_points[3] = cv::Point2f(s.width,s.height);  // lower right

    // Build quandrangle "de-skew" transform matrix values
    cv::Mat transform = cv::getPerspectiveTransform( source_points, dest_points  );
    // Apply the deskew transform
    cv::warpPerspective( capturedFrame, deskewedMat, transform, s, cv::INTER_CUBIC );

    return deskewedMat;
}

谢谢,我会关注这个问题! - Jakob Halskov
@JakobHalskov,你有尝试过这个方法吗?或者找到了其他的解决方案吗? - Buddhisthead
@JakobHalskov,如果你能尝试一下我的解决方案或其他人的解决方案就好了。这段代码是否不清晰或需要更多的解释? - Buddhisthead

0

还可以查看这个带答案的问题:https://dev59.com/qF_Va4cB1Zd3GeqPX-j5 - brigadir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接