Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++ Builder
Войти
Регистрация
Восстановить пароль
 
Ne_sudba
2 / 2 / 0
Регистрация: 19.02.2015
Сообщений: 10
1

Вращение, масштабирование, сдвиг изображений. Работает, но есть баг

01.06.2018, 11:58. Просмотров 244. Ответов 5
Метки нет (Все метки)

Доброго дня.
Пытался решить задачу вращения, масштабирования и сдвига изображения.
Попробовал, наверное, все, что описано в интернетах. И через pixels, и через scanline, а теперь вот SetWorldTransform.
Самым быстрым способом похоже является SetWorldTransform. К тому же он освобождает от самостоятельного закрашивания пробелов, которые образуются при повороте.

Получился пока вот такой код:

Вызов функции:

C++
1
rotate_move_scale( bug1->Picture->Bitmap, bug2->Picture->Bitmap, back->Picture->Bitmap, Form1->horizontal_scale->Position / 100.0 , Form1->vertical_scale->Position / 100.0, angle);
Сама функция:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void rotate_move_scale( TBitmap * source, TBitmap * middle, TBitmap *dest, float x_aspect, float y_aspect, float new_angle)
//поворот
{
    //TBitmap *middle = new TBitmap;                                            //промежуточное изображение для масштабирования
    middle->Width = source->Width * x_aspect;                                   //увеличиваем размер промежуточного изображения
    middle->Height = source->Height * y_aspect;                                 //увеличиваем размер промежуточного изображения
 
 
    HDC dc;                                                                     //указатель на handler
    XFORM xform;
 
 
    //масштаб на промежуточном битмапе
    dc = middle->Canvas->Handle;                                                //где будем менять законы отрисовки
    middle->Canvas->FillRect(Rect(0,0,middle->Width,middle->Height));           //затираем канвас
 
    xform.eDx = 0.0f;
    xform.eDy = 0.0f;
    xform.eM11 = x_aspect;                                                      //масштаб по горизонтали
    xform.eM12 = 0.0f;
    xform.eM21 = 0.0f;
    xform.eM22 = y_aspect;                                                      //масштаб по вертикали
 
    SetGraphicsMode(dc, GM_ADVANCED);
    SetWorldTransform(dc, &xform);
    middle->Canvas->Draw(0,0,source);                                           //рисуем отмасштабированный результат
 
 
 
    //поворот и сдвиг на итоговый битмап
    dc = dest->Canvas->Handle;                                                  //где будем менять законы отрисовки
    dest->Canvas->FillRect(Rect(0,0,dest->Width,dest->Height));                 //затираем канвас
 
    new_angle = new_angle * 3.1416 / 180.0;                                     //перевод в радианы
    xform.eDx = Form1->horizontal_move->Position;                               //смещение по горизонтали
    xform.eDy = Form1->vertical_move->Position;                                 //смещение по вертикали
 
    xform.eM11 = cos(new_angle);
    xform.eM12 = sin(new_angle);
    xform.eM21 = -sin(new_angle);
    xform.eM22 = cos(new_angle);
 
    SetGraphicsMode(dc, GM_ADVANCED);
    SetWorldTransform(dc, &xform);
    dest->Canvas->Draw(0,0,middle);                                             //рисуем повернутый и сдвинутый результат
 
 
    // delete middle;
}

Промежуточное изображение пока что вынесено на форму, что бы видеть промежуточный результат.

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

При этом на промежуточном этапе видно, что масштабирование работает правильно.

Может кто подскажет, что я делаю не так ?
0
Миниатюры
Вращение, масштабирование, сдвиг изображений. Работает, но есть баг  
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.06.2018, 11:58
Ответы с готовыми решениями:

Масштабирование изображений в TImage
Доброго времени суток уважаемые программисты, пишу программу для просмотра...

Урок геометрии, масштабирование изображений
Задача: Есть картинка 100x100 px на которой нарисован смайлик необходимо...

Масштабирование С++ Builder , есть проект
Всем доброго времени суток, товарищи! Прошу помочь! Если можно, то оперативно,...

Вращение и масштабирование !
Нужно добавить вращение и масштабироваиние звезды . Подскажите как это сделать...

Перемещение, вращение и масштабирование в JavaFX
Приветствую вас знатоки Java(FX) Просто нереально как нуждаюсь в вашей помощи,...

5
gunslinger
случайный прохожий
1309 / 829 / 326
Регистрация: 20.07.2013
Сообщений: 2,329
03.06.2018, 21:57 2
Если я не ошибаюсь, нужно принудительно задавать ширину и высоту итогового изображения аналогично тому, как ты это делаешь для промежуточной картинки в строках № 5 и 6.
1
Dinkin
655 / 452 / 118
Регистрация: 31.05.2013
Сообщений: 2,378
Записей в блоге: 3
04.06.2018, 00:03 3
Доброго. Если не ошибаюсь, то для билдера нет стандартных средств поворота изображения на определенный угол без потери качества.
0
Ne_sudba
2 / 2 / 0
Регистрация: 19.02.2015
Сообщений: 10
04.06.2018, 00:24  [ТС] 4
Цитата Сообщение от gunslinger Посмотреть сообщение
Если я не ошибаюсь, нужно принудительно задавать ширину и высоту итогового изображения аналогично тому, как ты это делаешь для промежуточной картинки в строках № 5 и 6.
Спасибо - попробовал, задал размер при показе формы, с запасом. Ничего вроде бы не изменилось.

Не могу понять, как так получается, что операция отрисовки одного битмапа на другой через Draw как то криво работает.

На первом мы видим, что картинка отмасштабирована. И информация о пикселях содержится в битмапе. По крайней мере строк у изображения стало больше.

Но почему в конечном битмапе изображение становится таким же, как было до масштабирования(по количеству строк)?

Может это SetWorldTransform как то влияет (когда из первого копируем во второй, задаем параметры трансформа - маштабирование- , и когда копируем из второго в третий, то эти же параметры для второго не дают нормально скопировать?)


Доброго. Если не ошибаюсь, то для билдера нет стандартных средств поворота изображения на определенный угол без потери качества.
не пойму. я привел код - это не средства билдера, это Win api. Ну и о повороте без потерь я ничего не говорил вроде бы. В моем проекте нужно отмаштабировать, повернуть и сдвинуть изображение. Вроде как почти получилось.

Про качество я упомянул, что бы хоть как то описать, что происходит. Попробую еще раз.

Была картинка 50 на 50 пикселей. Мы ее уменьшаем в 2 раза - она становится 25 на 25.
Потом копируем на новый битмап - там она снова становится 50 на 50. Только видно, что качество ухудшилось. Как будто из 25 на 25 снова растянули к 50 на 50. Почему это происходит при выполнении Draw - я пока не понял.
0
Dinkin
655 / 452 / 118
Регистрация: 31.05.2013
Сообщений: 2,378
Записей в блоге: 3
04.06.2018, 00:36 5
Цель то какая?
0
Ne_sudba
2 / 2 / 0
Регистрация: 19.02.2015
Сообщений: 10
04.06.2018, 14:08  [ТС] 6
Да вроде бы цель описывал:
В моем проекте нужно отмаштабировать, повернуть и сдвинуть изображение. Вроде как почти получилось.

По теме - у меня все получилось.

Оказывается, если для битмапа сделать SetWorldTransform, то при отрисовке его на другой битмап, эти же правила SetWorldTransform мешают сделать это правильно. Поэтому нужно перед выгрузкой куда либо применить старые правила.

Выкладываю рабочий код, вдруг кому то поможет:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
void rotate_move_scale( TBitmap * source, TBitmap *dest, float x_aspect, float y_aspect, float new_angle)
//поворот
{
    TBitmap *middle = new TBitmap;                                          //промежуточное изображение для масштабирования
    middle->Width = source->Width * x_aspect;                                   //увеличиваем размер промежуточного изображения
    middle->Height = source->Height * y_aspect;                                 //увеличиваем размер промежуточного изображения
 
 
    HDC dc;                                                                     //указатель на handler
    XFORM xform, old_xform;                                                     //свойства трансформирования
 
 
    //масштаб на промежуточном битмапе
    dc = middle->Canvas->Handle;                                                //где будем менять законы отрисовки
    middle->Canvas->FillRect(Rect(0,0,middle->Width,middle->Height));           //затираем канвас
 
    xform.eDx = 0.0f;
    xform.eDy = 0.0f;
    xform.eM11 = x_aspect;                                                      //масштаб по горизонтали
    xform.eM12 = 0.0f;
    xform.eM21 = 0.0f;
    xform.eM22 = y_aspect;                                                      //масштаб по вертикали
 
    SetGraphicsMode(dc, GM_ADVANCED);
    GetWorldTransform(dc,&old_xform);                                           //сохраняем старые параметры
    SetWorldTransform(dc, &xform);                                              //применяем новые параметры
    middle->Canvas->Draw(0,0,source);                                           //рисуем отмасштабированный результат
    SetWorldTransform(dc, &old_xform);                                          //возвращаем старые параметры
 
 
 
 
    //поворот и сдвиг на итоговый битмап
    dc = dest->Canvas->Handle;                                                  //где будем менять законы отрисовки
 
 
    dest->SetSize(500,500);
    dest->Canvas->FillRect(Rect(0,0,dest->Width,dest->Height));                 //затираем канвас
 
    new_angle = new_angle * 3.1416 / 180.0;                                     //перевод в радианы
    xform.eDx = 0; //Form1->horizontal_move->Position;                                  //смещение по горизонтали
    xform.eDy = 0; //Form1->vertical_move->Position;                                //смещение по вертикали
 
    xform.eM11 = cos(new_angle);
    xform.eM12 = sin(new_angle);
    xform.eM21 = -sin(new_angle);
    xform.eM22 = cos(new_angle);
 
    SetGraphicsMode(dc, GM_ADVANCED);
    GetWorldTransform(dc,&old_xform);                                           //сохраняем старые параметры
    SetWorldTransform(dc, &xform);
 
    SetViewportOrgEx(dc,100,100,NULL);
 
 
    dest->Canvas->Draw(-100,-100,middle);                                               //рисуем повернутый и сдвинутый результат
    SetWorldTransform(dc, &old_xform);                                          //возвращаем старые параметры
 
 
 
    delete middle;
}
1
04.06.2018, 14:08
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.06.2018, 14:08

Масштабирование и сдвиг Canvas
В первый раз использую канвас, задача - отображение по координатам...

Сдвиг и масштабирование графика функции
Привет!) Написал программу, которая рисует график функции. Как сделать...

Построение прямоугольника,его масштабирование,вращение вокруг осей и перенос
Здравствуйте!Помогите пожалуйста найти ошибку в коде...программа запускается,но...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru