Qt使用QTransform组合两个图像

时间:2012-05-27 10:33:45

标签: qt image-processing linear-algebra qimage

我遇到的问题可能很容易解决,但我说得不对: 我有两个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);

只要我只改变参考位置一切正常。使用缩放和/或旋转时,图像也可以正确缩放和旋转,但不会放在正确的位置(前景的图像中心与参考点不匹配)。 转换管道有问题吗?我犯了错误吗?

1 个答案:

答案 0 :(得分:3)

您需要颠倒您在QTransform上执行的陈述的顺序。订单必须与直觉思维相反。这与线性代数中变换矩阵的矩阵乘法有关。 (转换矩阵的Change of basis ...)问题在于转换适用于源坐标系,这是一种不直观的。

请记住:每当您想要应用多个转换时,请按照对图像进行反向顺序进行转换。

有关示例,请参阅the documentation of QTransform中的示例代码:

  

将文字缩放到半宽,然后顺时针旋转45度,然后将其原点移动到(50,50):

     

enter image description here

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);