如何在2D图像中对不规则形状应用纹理? [英] How to apply texture on irregular shapes in 2d image?

查看:40
本文介绍了如何在2D图像中对不规则形状应用纹理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将纹理应用于UIColor图案图像中的CALayer。纹理正在应用,但它没有正确的透视变换。看起来我的绘画逻辑有一个问题,即我需要使用纹理图像并将其映射到不规则形状上。我做了一些研究,知道这件事可以通过OpenGL或金属来实现,通过将纹理图像映射到2D图像中的不规则形状。

寻找某种指导,我如何才能正确透视转换磁贴图案?

        let image = UIImage(named: "roofTiles_square")?.flattened
        
        if let realImage = image {
            let color = UIColor(patternImage: realImage)
            controller.quadView.quadLayer.fillColor = color.cgColor
        }

如有任何帮助,将不胜感激。

谢谢

推荐答案

我正在撰写详细的解决方案,但我希望确保我解决的问题是正确的。我们的计划是创建一种变换,使屋顶瓦片图案(或任何此类图案)的一个版本正确扭曲,以便当映射到右侧图像中的四边形时,正确透视扭曲?即,四元组abc被映射到四元组A‘B’C‘e’?

第一步是计算将四元组ABCD映射到四元组A‘B’C‘’的homographyOpenCV provides methods for this,但让我们自己来计算。我们正在搜索一个3x3矩阵H,它将点A、B、C、D映射到点A‘、B’、C‘、D’,如下所示(实际上我们将以相反的方式进行):

使用3D齐次向量(x,y,w)允许我们在3D中工作,除以w提供了必要的视角缩短(长话短说)。 结果表明,H的任意比例倍数都有效,这意味着它只有8个自由度(而不是完整的3*3=9)。这意味着我们希望HA‘A的比例倍数,因此它们的叉积为零:

如果我们计算叉积,我们可以将最后一个方程式重写为

上述最后一个方程式实际上是前两个方程式的线性组合(将第一个方程式乘以x,将第二个方程式乘以y,然后将它们相加,得出第三个方程式)。因为第三个方程是线性相关的,所以我们把它扔掉,只用前两个。将第二个方程求反、交换,然后将其转换为矩阵形式后,我们得到

这样一点对应A‘-A会产生两个方程。 如果我们有n个点对应,我们得到2n个方程:

我们需要n>;=4至少有8个方程才能得到正确的解;也就是说,我们需要至少4个(非共线)点。 因此,我们有一个齐次的方程组,它 我们使用singular value decomposition

解决

显然,平凡的解h=0是有效的,但它不是很有用。 将h设置为V的最后一列将导致最小平方 我们的系统的误差解,其中h是单位长度。

让我们为您的特定示例计算H。让我们假设消息的来源 要变换的图像为WXH=500x300,因此A=(0,0)、B=(W,0)、C=(0,H)和D=(W,H)。目标图像是484x217,我找到了 屋顶的角点为A‘=(70.741.3),B’=(278.8,76.3), C‘=(136.4,121,2)和D’=(345.1,153,2)。我将使用Eigen 做计算吧。所以我将加载我的源和目标 指向矩阵:

#include <Eigen/Dense>
...
constexpr double W = 500;
constexpr double H = 300;
constexpr size_t N = 4;

Eigen::Matrix<double,2,N> SRC;
SRC <<
    0, W, 0, W,
    0, 0, H, H;
Eigen::Matrix<double,2,N> DST;
DST <<
    70.7, 278.8, 136.4, 345.1,
    41.3,  76.3, 121.2, 153.2;

我如上所述构造8x9矩阵A

Eigen::Matrix<double,2*N,9> A;
A.setZero();
for (size_t i = 0; i < N; i++) {
    const double x_ = DST(0,i), y_ = DST(1,i);
    const double x  = SRC(0,i), y  = SRC(1,i);
    A(2*i,0) = A(2*i+1,3) = x_;
    A(2*i,1) = A(2*i+1,4) = y_;
    A(2*i,2) = A(2*i+1,5) = 1;
    A(2*i,6) = -x*x_;
    A(2*i,7) = -x*y_;
    A(2*i,8) = -x;
    A(2*i+1,6) = -y*x_;
    A(2*i+1,7) = -y*y_;
    A(2*i+1,8) = -y;
}
然后我计算奇异值分解,从 V的最后一列,并将结果存储在3x3矩阵中:

Eigen::JacobiSVD<Eigen::Matrix<double,2*N,9>> svd(A, Eigen::ComputeFullV);
Eigen::Matrix<double,9,1> h = svd.matrixV().col(8);
Eigen::Matrix3d Homography;
Homography <<
    h(0), h(1), h(2),
    h(3), h(4), h(5),
    h(6), h(7), h(8);

生成所需的3x3矩阵H:

  -0.016329     0.013427      0.599927
   0.004571    -0.0271779     0.799277
   1.78122e-06 -2.83812e-06  -0.00613631

我们可以使用OpenCV查看示例扭曲图像。 我加载我的源纹理和我的单应性H,并使用OpenCV warpPerspective function

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>

int main() {
    cv::Mat sourceImage = imread("texture.png", cv::IMREAD_COLOR);
    cv::Matx33d H(-0.016329, 0.013427, 0.599927,
                  0.004571, -0.0271779, 0.799277,
                  1.78122e-06, -2.83812e-06, -0.00613631);
    cv::Mat destImage;
    cv::warpPerspective(sourceImage, destImage, H, cv::Size(487,217),
                        cv::INTER_LINEAR | cv::WARP_INVERSE_MAP);
    cv::imwrite("warped.png", destImage);
    return 0;
}

结果看起来可信:

这篇关于如何在2D图像中对不规则形状应用纹理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆