Create QTransform given 4 points defining the transformed unit square
Given 4 points being be the result of
QPolygon poly = transform.mapToPolygon(QRectF(0, 0, 1, 1));
how can I find QTransform transform
? (Even better: also given an arbitrary source rectangle)
Motivation: Given the four corner points of an image to be drawn in a perspectively distorted coordinate system, how can I draw the image using QPainter?
This is a screenshot illustrating the problem in GIMP, where one can transform a layer by moving around the 4 corners of the layer. This results in a perspective transformation. I want to do exactly the same in a Qt application. I know that QTransform is not restricted to affine transformations but can also handle perspective transformations.
You should be able to do this with QTransform.squareToQuad
. Just pass it the QPolygonF
you want to transform to.
I've sometimes had some issues getting squareToQuad to do what I want, and have had to use QTransform.quadToQuad
instead, defining my own starting quad, but you might have more luck.
I think I found a solution, which calculates the transformation matrix step by step.
// some example points:
QPointF p1(1.0, 2.0);
QPointF p2(2.0, 2.5);
QPointF p3(1.5, 4.0);
QPointF p4(3.0, 5.0);
// define the affine transformation which will position p1, p2, p3 correctly:
QTransform trans;
trans.translate(p1.x(), p1.y());
trans.scale(p2.x() - p1.x(), p3.y() - p1.y());
trans.shear((p3.x() - p1.x()) / trans.m11(), (p2.y() - p1.y()) / trans.m22());
Until now, trans describes a parallelogram transformation. Within this paralellogram, I find p4 (relatively) in the next step. I think that this can be done using a direct formula not involving an inversion of trans.
// relative position of the 4th point in the transformed coordinate system:
qreal px = trans.inverted().map(p4).x();
qreal py = trans.inverted().map(p4).y();
// this defines the perspective distortion:
qreal y = 1 + (py - 1) / px;
qreal x = 1 + (px - 1) / py;
The values x
and y
are hard to explain. Given only one of them (the other set to 1
), this defines the relative scaling of p4
only. But a combination of both x and y perspective transformation, the meaning of x and y are difficult; I found the formulas by trial and error.
// and thus the perspective matrix:
QTransform persp(1/y, 0, 1/y-1,
0, 1/x, 1/x-1,
0, 0, 1);
// premultiply the perspective matrix to the affine transformation:
trans = persp * trans;
Some tests showed that this leads to the correct results. However, I did not tested special cases like those where two points are equal or one of them is on the line segment between two others; I think that this solution might break in such situations.
Therefore, I still search for some direct formulas for the matrix values m11
, m12
... m33
, given the point coordinates p1.x()
, p1.y()
... p4.x()
, p4.y()
.
上一篇: 存储排序顺序/优先级的最佳方法?