我遇到的问题可能很容易解决,但我说得不对:
我有两个QImages,一个固定大小的背景图像imgBg
,另一个QImage imgFg
应该使用仿射变换进行变换,然后在背景图像上绘制(和剪裁)。
仿射变换如下:
这是我到目前为止所做的:
// Setup transform
QTransform trans;
trans.translate(-imgFg.width()/2, -imgFg.height()/2); // move center of image to origin
trans.scale(scaleFac, scaleFac);
trans.rotate(angleDegrees);
trans.translate(imgFg.width()/2, imgFg.height()/2);
// Transform foreground image
imgFg = imgFg.transformed(trans);
// Paint on background image
QPointF referencePos(imgBg.width()/3, imgBg.height()/2); // some reference position
QPainter painter(&imgBg);
painter.drawImage(referencePos - QPointF(imgFg.width()/2, imgFg.height()/2), imgFg);
只要我只改变参考位置一切正常。使用缩放和/或旋转时,图像也可以正确缩放和旋转,但不会放在正确的位置(前景的图像中心与参考点不匹配)。 转换管道有问题吗?我犯了错误吗?
答案 0 :(得分:3)
您需要颠倒您在QTransform
上执行的陈述的顺序。订单必须与直觉思维相反。这与线性代数中变换矩阵的矩阵乘法有关。 (转换矩阵的Change of basis ...)问题在于转换适用于源坐标系,这是一种不直观的。
请记住:每当您想要应用多个转换时,请按照对图像进行的反向顺序进行转换。
有关示例,请参阅the documentation of QTransform中的示例代码:
将文字缩放到半宽,然后顺时针旋转45度,然后将其原点移动到(50,50):
QTransform transform; transform.translate(50, 50); transform.rotate(45); transform.scale(0.5, 1.0);
另一个问题是你应该通过考虑缩放因子将图像转换回原点(感谢Mat在问题评论中指出这一点)。
应用于您的代码段(从下到上阅读直观的操作顺序):
// Setup transform
QTransform trans;
trans.translate(imgFg.width()*scaleFac/2, imgFg.height()*scaleFac/2);
trans.rotate(angleDegrees);
trans.scale(scaleFac, scaleFac);
trans.translate(-imgFg.width()/2, -imgFg.height()/2);
最后但并非最不重要的一点是,您希望将图像的中心作为新原点(参考点),因此您不应该翻译(现在是第一个操作;在您的代码中最后一个一)。然后只需在参考点绘制图像,而不是添加另一个尺寸/ 2。此外,您不应将变换应用于图像,然后绘制此图像;至少它不是好风格。只需将变换应用于画家并在之后取消应用。
QTransform trans;
trans.scale(scaleFac, scaleFac);
trans.rotate(angleDegrees);
trans.translate(imgFg.width()/2,imgFg.height()/2);
// Save old transform (only needed if you use other transformations)
const QTransform &oldTrans = painter.transform();
// Apply new transform
painter.setTransform(trans);
// Paint image at reference point
painter.drawImage(referencePoint, imgFg);
// Restore transform
painter.setTransform(oldTrans);