Russian Qt Forum
Сентябрь 30, 2024, 16:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Трансформ QPainter и QImage  (Прочитано 7719 раз)
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« : Май 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 должен как раз использовать ф-ии имаджа для рисования. Это я туплю, или задача нерешаема?
Есть мысль, что дело может быть в матрице трансформации, так как они разные, то и результаты могут отличаться. Можно ли как-то привести всё к одной матрице?
« Последнее редактирование: Май 29, 2013, 10:30 от Авварон » Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Май 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-канала.
Записан

Qt 5.11/4.8.7 (X11/Win)
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #2 : Май 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 формат проверить.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Май 29, 2013, 16:26 »

Поворот имеджа увеличивает его размеры, и это растровая операция с какой-то потерей качества. Если Вы рисуете "наискосок", то эффект тот же самый, т.е. рисование "0.png" сводится к его повороту.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Май 29, 2013, 16:33 »

Поворот имеджа увеличивает его размеры, и это растровая операция с какой-то потерей качества. Если Вы рисуете "наискосок", то эффект тот же самый, т.е. рисование "0.png" сводится к его повороту.

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

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Май 29, 2013, 16:53 »

Это понятно, но я результирующий имадж пейнтера увеличиваю пропорционально. И там и там наблюдается потеря качества, но почему-то по-разному.
Не вижу где Вы его увеличиваете, но если так - совпадения не получить, растровые преобразования не линейны/"афинны". Идите по шагам drawImage (или см исходники). Так или иначе ф-ция/метод поворота имеджа позовется, никуда он не денется. Отрисовку картинки возможно удастся воспроизвести (сбив параметры), но с др рисованием (напр хотя бы линий) тождества не будет.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #6 : Май 29, 2013, 17:13 »

ф-ция/метод поворота имеджа позовется, никуда он не денется. Отрисовку картинки возможно удастся воспроизвести (сбив параметры), но с др рисованием (напр хотя бы линий) тождества не будет.

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

Сообщений: 2921



Просмотр профиля
« Ответ #7 : Май 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() );
Записан

Qt 5.11/4.8.7 (X11/Win)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Май 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);
// рисуем имедж
 
Писал здесь, может где-то насвистел  Улыбающийся
« Последнее редактирование: Май 29, 2013, 18:38 от Igors » Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #9 : Май 29, 2013, 18:46 »

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

Записан

Qt 5.11/4.8.7 (X11/Win)
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #10 : Май 29, 2013, 22:57 »

Спасибо, завтра оба способа попробую, сейчас компа нет. Отпишусь как и что.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #11 : Май 30, 2013, 11:22 »

Да нет, центровку делает QImage::transformed() через QImage::trueMatrix().
Только вот, если не делать так же, то по высоте будет смещение в пол-пикселя.

Да, с труматрикс работает, буду дальше разбираться.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.341 секунд. Запросов: 22.