【问题标题】:Applying QTransform on QPainter - how to find translations在 QPainter 上应用 QTransform - 如何查找翻译
【发布时间】:2017-03-02 23:19:39
【问题描述】:

我想在 QImage 上应用某些转换 - 由于性能限制,如果可能,我想在渲染时应用这些转换。

我需要的变换 - 旋转 90、180、270 度和垂直镜像。

我将QGraphicsScene 渲染为QImage
我希望将结果旋转 (0/90/180/270) 或垂直镜像。

我的原始代码很简单:

QImage image = QImage(wOutput, hOutput, QImage::Format_Mono);
image.fill(QColor(Qt::white).rgb());
QPainter painter;
painter.begin(&image);
outputScene->render(&painter);
painter.end();

要旋转,我认为在绘画之前旋转QPainter 会很有效——这样我就不必在后期处理中执行额外的转换。 (我正在计划一个内存和速度非常有限的设备,以及 Qt4.8)

它应该可以工作......但除了旋转我还必须添加一个翻译,我不知道多少。

如果没有翻译,我只会得到空白图像。

此外,旋转到 90/-90 我会得到更小的图像。所以我需要扩展...多少?

我的代码尝试转换(旋转和镜像)图像:

#include <QApplication>
#include <QGraphicsScene>
#include <QImage>
#include <QPainter>
#include <QTransform>

QImage badProcessScene(QGraphicsScene *s, int orientation, bool mirror);
QImage wantProcessScene(QGraphicsScene *s, int orientation, bool mirror);

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene* s = new QGraphicsScene(-20, -100, 800, 600);
    s->addText("abcd", QFont("Arial", 20));
    s->setBackgroundBrush(Qt::red);

    // orientation = -90, 0, 90, 180;
    int orientation = -90;
    // vertical mirror true/false
    bool mirror = true;

    // what I am trying to do
    QImage im = wantProcessScene(s, orientation, mirror);
    im.save("test.bmp");

    // what I would like to come out like (Qt version)
    QImage im1 = badProcessScene(s, orientation, mirror);
    im1.save("test1.bmp");

    a.exit();
    return 0;
}

// Bad version, though functional - typical approach, of rotating images after being rendered
QImage badProcessScene(QGraphicsScene *s, int orientation, bool mirror)
{
    int wOutput = s->width(), hOutput = s->height();

    QImage image = QImage(wOutput, hOutput, QImage::Format_ARGB32_Premultiplied);
    image.fill(QColor(Qt::white).rgb());

    QPainter painter;
    painter.begin(&image);
    s->render(&painter);
    painter.end();

    if(mirror)
        image = image.mirrored(0, 1);
    image = image.transformed(QMatrix().rotate(orientation));

    return image;
}

// Desired but needs adjustments 
QImage wantProcessScene(QGraphicsScene* s, int orientation, bool mirror)
{
    int wOutput = s->width(), hOutput = s->height();

    // translation
    int wTr = wOutput, hTr = hOutput;
    // coefficients of transformation matrix
    qreal m11 = 1, m12 = 0, m21 = 0, m22 = 1, m31 = 0, m32 = 0;
    switch(orientation)
    {
    //case 0: break;
    case -90: wTr = hOutput; hTr = wOutput; m11 = 0; m12 = -1; m21 = 1; m22 = 0; 
              m31 = x?; m32 = x?; break;  
    case 180: wTr = wOutput; hTr = hOutput; m11 = -1, m22 = -1; 
             m31 = x?; m32 = x?; break;  
    case 90: wTr = hOutput; hTr = wOutput; m11 = 0; m12 = 1; m21 = -1; m22 = 0; 
              m31 = x?; m32 = x?; break;  
    }

    QImage image = QImage(wTr, hTr, QImage::Format_ARGB32_Premultiplied);
    image.fill(QColor(Qt::white).rgb());

    QPainter painter;
    painter.begin(&image);

    QTransform painterTransform;
    if(mirror)
    {
        // I have seen that negative scaling actually flips
        m22 *= -1;
        // I am guessing on shifts...
        switch(orientation)
        {
        case 0: m31 = x?; m32 = x?; break;  
        case 180: m31 = x?; m32 = x?; break; 
        case 90: m31 = x?; m32 = x?; break;
        case -90: m31 = x?; m32 = x?; break; 
        }
    }

    painterTransform.setMatrix(m11, m12, 0, m21, m22, 0, m31, m32, 1);

    painter.setTransform(painterTransform);
    s->render(&painter);
    painter.end();

    return image;
}

请注意上面的代码 - 我有 2 个函数:

  • 我正在尝试做的事情,通过在渲染前旋转 QPainter (wantProcessScene)
  • Qt 执行“转换”的功能——它遍历图像像素并在图像已经渲染后移动它们——在非常大的图像、内存和 CPU 受限的设备上非常慢;它就像我在代码中所说的那样工作,这是不可接受的。 (badProcessScene)

我无法找出旋转 180/90/-90 时的平移和缩放公式(因为 90/-90 的结果似乎更小)。

至于镜像,我希望我将大小调整为 -1 的想法可行 - 但我有同样的问题来确定班次。

如果换档不正确,我只会看到白色图像。当我让它工作时,90/-90 旋转似乎会产生更小的图像(将更大的尺寸适合更小的尺寸,保持纵横比)。

请帮我弄清楚如何执行这些转换。我想要一个基于角度确定平移(并缩放以将图像重置为相同大小)的矩阵 - 而不是这些奇怪的角度。

【问题讨论】:

  • 可能是一个愚蠢的问题,但你不能在第二个函数中渲染之前转换图像吗?
  • @ymoreau - 在渲染之前我没有图像;而且我不想转换图像,我不想使用第二个功能。这就是重点——图像变换遍历每个像素。对于需要很长时间的超大图像和小内存/cpu 设备。我想要没有工作的结果。

标签: qt transform qpainter qimage


【解决方案1】:

我通过旋转QPainter 来发布执行旋转和镜像的功能。

我无法得到一个实际的公式 - 大部分是反复试验和一遍又一遍地重绘一个对象,它的旋转。

一旦我弄清楚系数是什么,它就变得有点合乎逻辑了。

对于调整大小问题 - 解决方案是将“目标”保持在原始渲染矩形。

QImage processScene(QGraphicsScene* s, int orientation, bool mirror)
{
    int wOutput = s->width(), hOutput = s->height();
    QRect target(0, 0, wOutput, hOutput);

    // translation
    int wTr = wOutput, hTr = hOutput;

    // coefficients of transformation matrix
    qreal m11 = 1, m12 = 0, m21 = 0, m22 = 1, m31 = 0, m32 = 0;
    switch(orientation)
    {
    //case 0: break;
    case -90: wTr = hOutput; hTr = wOutput; m11 = 0; m12 = -1; m21 = 1; m22 = 0;
        m32 = wOutput; break;
    case 180: wTr = wOutput; hTr = hOutput; m11 = -1, m22 = -1;
        m31 = wOutput; m32 = hOutput; break;
    case 90: wTr = hOutput; hTr = wOutput; m11 = 0; m12 = 1; m21 = -1; m22 = 0;
        m31 = hOutput; break;
    }

    if(mirror)
    {
        switch(orientation)
        {
        case 0: m22 = -1; m32 = hOutput; break;
        case 180: m22 = 1; m32 = 0; break;
        case 90: m21 = 1; m31 = 0; break;
        case -90: m21 = -1; m31 = hOutput; break;
        }
    }

    QTransform painterTransform;
    painterTransform.setMatrix(m11, m12, 0, m21, m22, 0, m31, m32, 1);

    QImage image = QImage(wTr, hTr, QImage::Format_Mono);
    image.fill(QColor(Qt::white).rgb());

    QPainter painter;
    painter.begin(&image);
    painter.setTransform(painterTransform);
    s->render(&painter, target);
    painter.end();

    return image;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 2014-04-19
    • 1970-01-01
    • 2013-07-27
    • 2021-11-26
    相关资源
    最近更新 更多