How to apply texture on irregular shapes in 2d image?(如何在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‘’的homography。OpenCV 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图像中对不规则形状应用纹理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在2D图像中对不规则形状应用纹理?
基础教程推荐
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- Android:对话框关闭而不调用关闭 2022-01-01
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01