2016-10-20 12 views
1

Я хотел бы применить определенные преобразования на QImage - и из-за ограничений производительности я хотел бы применить эти преобразования во время рендеринга, если это возможно.Применение QTransform на QPainter - как найти переводы

Необходимые преобразования - поворот 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 processScene(QGraphicsScene *s, int orientation, bool mirror); 
QImage otherProcessScene(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 = processScene(s, orientation, mirror); 
    im.save("test.bmp"); 

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

    a.exit(); 
    return 0; 
} 

QImage processScene(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; 
} 

QImage otherProcessScene(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; 
} 

Примечание в приведенном выше коде - У меня есть 2 функции:
- то, что я пытаюсь сделать, путем вращения QPainter до рендеринга
- тот, который делает Qt «преобразует» - который перебирает пиксели изображения и перемещает их после того, как изображение уже было обработано, - и на очень больших изображениях на устройствах с ограниченным объемом памяти и на процессорах очень медленно; Он работает, как я сказал в коде, и это неприемлемо.

Я не смог найти формулу для перевода и масштабирования (потому что для 90/-90 результат кажется меньшим) при вращении 180/90/-90.

Что касается зеркала, я надеюсь, что моя идея изменения размера на -1 работает, но у меня такая же проблема определения сдвигов.

С неправильными сдвигами я просто вижу белое изображение. По мере того как я получаю это, чтобы работать, повороты 90/-90, кажется, приводят к меньшему изображению (которое приспосабливает больший размер к меньшему, сохраняя пропорции).

Пожалуйста, помогите мне выяснить, как выполнить эти преобразования. Мне бы понравилась матрица, которая определяет переводы (и масштабирование для возврата изображений назад к одному и тому же размеру) на основе угла - а не странные углы именно этих.

+0

Может быть, это глупый вопрос, но разве вы не можете просто преобразовать изображение перед рендерингом во второй функции? – ymoreau

+0

@ymoreau - у меня нет изображения, до рендеринга; и я не хочу преобразовывать изображение, я не хочу использовать вторую функцию. В этом весь смысл - преобразования изображений проходят через каждый пиксель. Для чрезвычайно больших изображений и небольших устройств памяти/процессора, которые занимают очень много времени. Я хочу получить результат без работы. – Thalia

ответ

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