iPhone 图像拉伸(歪斜) [英] iPhone image stretching (skew)

查看:41
本文介绍了iPhone 图像拉伸(歪斜)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何倾斜图像?例如,每个角都有一个带有坐标的 CGPoint - p1、p2、p3、p4.然后,我需要设置 - p4.x+=50, p4.y+=30.所以这个角 (p4) 应该在 2D 透视图中被拉伸,图像应该被扭曲.


(来源:polar-b.com)

我尝试使用CATransform3D,但似乎不能以这种方式完成,因为它只是改变视角(旋转,使一侧更近/更远).或许 CGAffineTransform 会有用?

如果你知道答案,请写一个示例代码.

提前致谢

解决方案

无法使用 CGAffineTransform.仿射变换总是可以分解为平移、旋转、剪切和缩放.它们都将平行四边形映射成平行四边形,而您的变换不会.

对于您的转换,可以分两步完成.一种将正方形转换为梯形.

p1-----p2​​ p1-----p2||-->|p3-----p4 p3--------p4'

另一个垂直方向.一个简单的转换规则是

 y - cx' = (x - p1.x) * ———————— + p1.xp1.y - cy' = y

其中 c 是连接 p1 和 p3 以及 p2 和 p4 的线的交点的 y 坐标.

现在注意变换中的 x*y 因子.这表明这种变换非线性.因此,CATransform3D 也不能将其作为 2D 变换来执行.

然而,向量

[x, y, z, w=1]

将转换为实际的 3D 矢量

(x/w, y/w, z/w)

在投影之前,如果 CA 遵循通常的 3D 计算图形规则,那么您可以使用变换来作弊"

[ P ..Q ] [ x ] [ x' ][ .R .S ] [ y ] = [ y' ][ ..1 .] [ Z Z' ][ ..U ] [ 1 ] [ w' ]

使用适当的 P、Q、R、S、T、U 将 4 个点映射到预期位置.(在大多数情况下,6 个唯一坐标和 6 个变量应该正好有 1 个解.)

找到这 6 个常量后,您可以制作一个 CATransform3D.注意结构定义是

struct CATransform3D{CGFloat m11、m12、m13、m14;CGFloat m21、m22、m23、m24;CGFloat m31、m32、m33、m34;CGFloat m41、m42、m43、m44;};typedef struct CATransform3D CATransform3D;

因此您可以直接更改矩阵元素,而不是依赖 CATransform3DMake 函数.(由于使用行或列向量的惯例,您可能需要执行转置.)

<小时>

获得将矩形((X, Y), (W, H))转换为任意四边形((x1a, y1a), (x2a, y2a); (x3a, y3a), (x4a, y4a)的变换)),使用这个函数(你可能需要转置):

function compute_transform_matrix(X, Y, W, H, x1a, y1a, x2a, y2a, x3a, y3a, x4a, y4a) {var y21 = y2a - y1a,y32 = y3a - y2a,y43 = y4a - y3a,y14 = y1a - y4a,y31 = y3a - y1a,y42 = y4a - y2a;var a = -H*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42);var b = W*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43);var c = H*X*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42) - H*W*x1a*(x4a*y32 - x3a*y42 + x2a*y43) - W*Y*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43);var d = H*(-x4a*y21*y3a + x2a*y1a*y43 - x1a*y2a*y43 - x3a*y1a*y4a + x3a*y2a*y4a);var e = W*(x4a*y2a*y31 - x3a*y1a*y42 - x2a*y31*y4a + x1a*y3a*y42);var f = -(W*(x4a*(Y*y2a*y31 + H*y1a*y32) - x3a*(H + Y)*y1a*y42 + H*x2a*y1a*y43 + x2a*Y*(y1a)- y3a)*y4a + x1a*Y*y3a*(-y2a + y4a)) - H*X*(x4a*y21*y3a - x2a*y1a*y43 + x3a*(y1a - y2a)*y4a + x1a*y2a*(-y3a + y4a)));var g = H*(x3a*y21 - x4a*y21 + (-x1a + x2a)*y43);var h = W*(-x2a*y31 + x4a*y31 + (x1a - x3a)*y42);var i = W*Y*(x2a*y31 - x4a*y31 - x1a*y42 + x3a*y42) + H*(X*(-(x3a*y21) + x4a*y21 + x1a*y43 - x2a*y43)+ W*(-(x3a*y2a) + x4a*y2a + x2a*y3a - x4a*y3a - x2a*y4a + x3a*y4a));返回 [[a,b,0,c],[d,e,0,f],[0,0,1,0],[g,h,0,i]];}

How do I skew an image? For example, each corner has a CGPoint with coords - p1, p2, p3, p4. Then, I need to set - p4.x+=50, p4.y+=30. So this corner (p4) should be stretched in a 2D perspective and the image should be distorted.


(source: polar-b.com)

I tried to use CATransform3D, but it seems that this cannot be done in such way, since it's only a change the perspective of view (rotate, bring closer/farther one side). Maybe CGAffineTransform can be useful?

If you know the answer, please write a sample code.

Thanks in advance

解决方案

Not possible with CGAffineTransform. An affine transform can always be decomposed into translations, rotations, shearing and scaling. They all map parallelograms into parallelograms, which your transform does not.

For your transform, it can be done in two steps. One to convert the square into a trapezoid.

p1-----p2       p1-----p2
 |     |   -->   |       
p3-----p4       p3--------p4'

Another to the vertical direction. A naive transformation rule is

                   y - c
x' = (x - p1.x) * ———————— + p1.x
                  p1.y - c
y' = y

where c is the y-coordinate of the intersection point of the lines joining p1 and p3, and p2 and p4.

Now notice the x*y factor in the transformation. This indicates such a transform is not linear. Therefore, CATransform3D cannot perform this as a 2D transform either.

However, the vector

[x, y, z, w=1]

will be converted to the actual 3D vector

(x/w, y/w, z/w)

before projection if CA follows usual 3D compute graphics rules, so you could "cheat" by using the transform

[ P . . Q ] [ x ]   [ x' ]
[ . R . S ] [ y ] = [ y' ]
[ . . 1 . ] [ z ]   [ z' ]
[ . T . U ] [ 1 ]   [ w' ]

with appropriate P, Q, R, S, T, U that maps the 4 points to the expected locations. (6 unique coordinates and 6 variables should have exactly 1 solution most of the cases.)

When you have found these 6 constants, you can craft a CATransform3D. Notice the structure definition is

struct CATransform3D
   {
   CGFloat m11, m12, m13, m14;
   CGFloat m21, m22, m23, m24;
   CGFloat m31, m32, m33, m34;
   CGFloat m41, m42, m43, m44;
};
typedef struct CATransform3D CATransform3D;

So you can directly change the matrix elements, instead of relying on the CATransform3DMake functions. (You may need to perform a transpose due to convention of using row or column vectors.)


To obtain the transform to convert a rectangle ((X, Y), (W, H)) to any quadrilateral ((x1a, y1a), (x2a, y2a); (x3a, y3a), (x4a, y4a)), use this function (you may need a transpose):

function compute_transform_matrix(X, Y, W, H, x1a, y1a, x2a, y2a, x3a, y3a, x4a, y4a) {
    var y21 = y2a - y1a, 
        y32 = y3a - y2a,
        y43 = y4a - y3a,
        y14 = y1a - y4a,
        y31 = y3a - y1a,
        y42 = y4a - y2a;

    var a = -H*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42);
    var b = W*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43);
    var c = H*X*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42) - H*W*x1a*(x4a*y32 - x3a*y42 + x2a*y43) - W*Y*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43);

    var d = H*(-x4a*y21*y3a + x2a*y1a*y43 - x1a*y2a*y43 - x3a*y1a*y4a + x3a*y2a*y4a);
    var e = W*(x4a*y2a*y31 - x3a*y1a*y42 - x2a*y31*y4a + x1a*y3a*y42);
    var f = -(W*(x4a*(Y*y2a*y31 + H*y1a*y32) - x3a*(H + Y)*y1a*y42 + H*x2a*y1a*y43 + x2a*Y*(y1a - y3a)*y4a + x1a*Y*y3a*(-y2a + y4a)) - H*X*(x4a*y21*y3a - x2a*y1a*y43 + x3a*(y1a - y2a)*y4a + x1a*y2a*(-y3a + y4a)));

    var g = H*(x3a*y21 - x4a*y21 + (-x1a + x2a)*y43);
    var h = W*(-x2a*y31 + x4a*y31 + (x1a - x3a)*y42);
    var i = W*Y*(x2a*y31 - x4a*y31 - x1a*y42 + x3a*y42) + H*(X*(-(x3a*y21) + x4a*y21 + x1a*y43 - x2a*y43) + W*(-(x3a*y2a) + x4a*y2a + x2a*y3a - x4a*y3a - x2a*y4a + x3a*y4a));

    return [[a,b,0,c],[d,e,0,f],[0,0,1,0],[g,h,0,i]];
}

这篇关于iPhone 图像拉伸(歪斜)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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