Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Авварон от Май 29, 2013, 10:28



Название: Трансформ QPainter и QImage
Отправлено: Авварон от Май 29, 2013, 10:28
День добрый. Внезапно, у меня возник интерес, можно ли сделать так, чтобы рисование пейнтером было идентичным тем изменениям, которые можно сделать с QImage'ем. Задача - я хочу рендерить сцену в картинку, полностью сохраняя качество (то есть, чтобы при повороте сцены с добавленной в неё картинкой результат рендеринга совпадал с поворотом имаджа).
Написал тест, он не проходит:

Код:
void PainterImageTest::test()
{
    QImage image(":/ABBAPOH.png");
    QImage result1;
    QImage result2;
    QVERIFY(!image.isNull());

    image = image.convertToFormat(QImage::Format_ARGB32);
    image.save("/home/arch/0.png");

    {
        result2 = QImage(image.size(), QImage::Format_ARGB32);
        QPainter p(&result2);
        p.drawImage(0, 0, image);
    }

    QVERIFY(image == result2); // passes

    qreal angle = -45;
    QTransform matrix;
    matrix.rotate(-angle);

    result1 = image.transformed(matrix, Qt::SmoothTransformation);

    {
        QSize size = result1.size();
        result2 = QImage(size, QImage::Format_ARGB32);
        result2.fill(QColor(255, 255, 255, 0));
        QPainter p(&result2);
        p.setRenderHint(QPainter::SmoothPixmapTransform);
        p.setRenderHint(QPainter::Antialiasing);
        p.setRenderHint(QPainter::HighQualityAntialiasing);
        QTransform matrix;
        matrix.translate(size.width() / 2.0, size.height() / 2.0);
        matrix.rotate(-angle);
        matrix.translate(-image.size().width() / 2.0, -image.size().height() / 2.0);
        p.setTransform(matrix);
        p.drawImage(0.0, 0.0, image);
    }

    QVERIFY(result1 == result2); // fails
}

По идее, ImageDevice должен как раз использовать ф-ии имаджа для рисования. Это я туплю, или задача нерешаема?
Есть мысль, что дело может быть в матрице трансформации, так как они разные, то и результаты могут отличаться. Можно ли как-то привести всё к одной матрице?


Название: Re: Трансформ QPainter и QImage
Отправлено: GreatSnake от Май 29, 2013, 15:20
Есть мысль, что дело может быть в матрице трансформации, так как они разные, то и результаты могут отличаться. Можно ли как-то привести всё к одной матрице?
Да, дело в матрице, но и не только в ней.
После
Код
C++ (Qt)
matrix.translate(-image.size().width() / 2.0, -image.size().height() / 2.0);
matrix.dy() != top_scope_matrix.dy(). Но даже, если dy-и уровнять, то картинки всё-равно будут разные. ???
Есть подозрение, что это происходит из-за alpha-канала.


Название: Re: Трансформ QPainter и QImage
Отправлено: Авварон от Май 29, 2013, 16:07
Да, дело в матрице, но и не только в ней.
После
Код
C++ (Qt)
matrix.translate(-image.size().width() / 2.0, -image.size().height() / 2.0);
matrix.dy() != top_scope_matrix.dy(). Но даже, если dy-и уровнять, то картинки всё-равно будут разные. ???
Есть подозрение, что это происходит из-за alpha-канала.

А как уравнять dy? У меня, вообще, с матрицами трансформации всегда было плоховато:)

А что не так с альфой? Можно попробовать сначала RGB формат проверить.


Название: Re: Трансформ QPainter и QImage
Отправлено: Igors от Май 29, 2013, 16:26
Поворот имеджа увеличивает его размеры, и это растровая операция с какой-то потерей качества. Если Вы рисуете "наискосок", то эффект тот же самый, т.е. рисование "0.png" сводится к его повороту.


Название: Re: Трансформ QPainter и QImage
Отправлено: Авварон от Май 29, 2013, 16:33
Поворот имеджа увеличивает его размеры, и это растровая операция с какой-то потерей качества. Если Вы рисуете "наискосок", то эффект тот же самый, т.е. рисование "0.png" сводится к его повороту.

Это понятно, но я результирующий имадж пейнтера увеличиваю пропорционально. И там и там наблюдается потеря качества, но почему-то по-разному.


Название: Re: Трансформ QPainter и QImage
Отправлено: Igors от Май 29, 2013, 16:53
Это понятно, но я результирующий имадж пейнтера увеличиваю пропорционально. И там и там наблюдается потеря качества, но почему-то по-разному.
Не вижу где Вы его увеличиваете, но если так - совпадения не получить, растровые преобразования не линейны/"афинны". Идите по шагам drawImage (или см исходники). Так или иначе ф-ция/метод поворота имеджа позовется, никуда он не денется. Отрисовку картинки возможно удастся воспроизвести (сбив параметры), но с др рисованием (напр хотя бы линий) тождества не будет.


Название: Re: Трансформ QPainter и QImage
Отправлено: Авварон от Май 29, 2013, 17:13
ф-ция/метод поворота имеджа позовется, никуда он не денется. Отрисовку картинки возможно удастся воспроизвести (сбив параметры), но с др рисованием (напр хотя бы линий) тождества не будет.

Вот тут
Код:
        QSize size = result1.size();
        result2 = QImage(size, QImage::Format_ARGB32);
я беру уже вычисленный размер после поворота (который больше исходного). Так что, размеры результирующих картинок совпадают.


Название: Re: Трансформ QPainter и QImage
Отправлено: GreatSnake от Май 29, 2013, 18:02
Похоже нашел в чём дело)
Замени
Код
C++ (Qt)
matrix.translate(-image.size().width() / 2.0, -image.size().height() / 2.0);
на
Код
C++ (Qt)
matrix = QImage::trueMatrix( matrix, image.width(), image.height() );


Название: Re: Трансформ QPainter и QImage
Отправлено: Igors от Май 29, 2013, 18:35
я беру уже вычисленный размер после поворота (который больше исходного). Так что, размеры результирующих картинок совпадают.
Центры координат разные, результаты должны разбежаться. Вначале Вы рисовали имедж в (0, 0) - верхнем левом углу исходного. Но когда результат увеличен поворотом - это соответствует уже др точке, Вам надо найти ее на увеличенном, установить начало координат в нее и сделать поворот

Код
C++ (Qt)
QTransform matrix;
matrix.rotate(-angle);
 
// смещение относительно центра
QPointF offset = matrix.map(QPointF(image.width() / 2. image.height() / 2));
 
// левый верхний угол в увеличенном
QPointF left_top = QPointF(size.width() / 2, size.height() / 2) - offset;
 
matrix = QTransform();
matrix.translate(left_top.x(), left_top.y());
matrix.rotate(-angle);
// рисуем имедж
 
Писал здесь, может где-то насвистел  :)


Название: Re: Трансформ QPainter и QImage
Отправлено: GreatSnake от Май 29, 2013, 18:46
Центры координат разные, результаты должны разбежаться. Вначале Вы рисовали имедж в (0, 0) - верхнем левом углу исходного. Но когда результат увеличен поворотом - это соответствует уже др точке, Вам надо найти ее на увеличенном, установить начало координат в нее и сделать поворот
Да нет, центровку делает QImage::transformed() через QImage::trueMatrix().
Только вот, если не делать так же, то по высоте будет смещение в пол-пикселя.



Название: Re: Трансформ QPainter и QImage
Отправлено: Авварон от Май 29, 2013, 22:57
Спасибо, завтра оба способа попробую, сейчас компа нет. Отпишусь как и что.


Название: Re: Трансформ QPainter и QImage
Отправлено: Авварон от Май 30, 2013, 11:22
Да нет, центровку делает QImage::transformed() через QImage::trueMatrix().
Только вот, если не делать так же, то по высоте будет смещение в пол-пикселя.

Да, с труматрикс работает, буду дальше разбираться.