C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как ускорить поворот картинки вокруг точки?
Мансур
Отправлено: 16.11.2003, 19:20


Не зарегистрирован







Для поворота картинки вокруг точки (IX0,IY0) я использую двойной цикл в следющ виде
Но в этом случае процесс идет слишком долго. Также потеряются некоторые пикселы.
Прошу высказать советы.Скажите как я смогу ускорить процесс этого аффинного преобразовании?
И не потерять пикселы?
Ответ прошу выслать также jmansur@lan.ab.az

double cb=cos(alfa);double sb=sin(alfa); // alfa уголь поворота

for (int x=0;xWidth;++x)
{
for (int y=0;yHeight;++y)
{

x1=(x-IX0)*cb+(y-IY0)*sb;
y1=-(x-IX0)*sb+(y-IY0)*cb;
// эти две строки формулы аффинного преобразования
Bitmap_2->Canvas->Pixels[x1+IX0][y1+IY0]=Bitmap_1->Canvas->Pixels[x][y];


}
}
Георгий
Отправлено: 17.11.2003, 22:49


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



И почему только в BCB нет встроенных профайлеров?
сделал я проверочный проектик
и получилось, что в следующем коде:
CODE
Profiler pr;
pr.SetPoints(9);
pr.EnterPoint(0);
Extended alpha,sb,cb;
alpha=this->CSpinEdit1->Value;
int x,y,Width,Height;
Extended IX0,IY0,x1,y1;
IX0=0;
IY0=0;
Graphics::TBitmap *bmp1, *bmp2;
pr.LeavePoint(0);
pr.EnterPoint(1);
bmp1=new Graphics::TBitmap;
bmp2=new Graphics::TBitmap;
pr.LeavePoint(1);
pr.EnterPoint(2);
bmp1->Assign(this->Image1->Picture->Bitmap);
Width=bmp1->Width;
Height=bmp1->Height;
bmp2->Width=Width;
bmp2->Height=Height;
pr.LeavePoint(2);
pr.EnterPoint(3);
alpha=alpha*M_PI/360.0;
SinCos(alpha,sb,cb);
IX0=Width/2;
IY0=Height/2;
pr.LeavePoint(3);
pr.EnterPoint(4);
for (int x=0;x<Width;++x)
for (int y=0;y<Height;++y)
{
pr.EnterPoint(5);
x1=(x-IX0)*cb+(y-IY0)*sb;
y1=-(x-IX0)*sb+(y-IY0)*cb;
pr.LeavePoint(5);
pr.EnterPoint(6);
// ýòè äâå ñòðîêè ôîðìóëû àôôèííîãî ïðåîáðàçîâàíèÿ
bmp2->Canvas->Pixels[x1+IX0][y1+IY0]=bmp1->Canvas->Pixels[x][y];
pr.LeavePoint(6);
}
pr.LeavePoint(4);
pr.EnterPoint(7);
this->Image2->Picture->Assign(bmp2);
pr.LeavePoint(7);
pr.EnterPoint(8);
delete bmp2;
delete bmp1;
pr.LeavePoint(8);
pr.ToStrings(this->Memo1->Lines);

распределение времён такое:
[#точки] [среднее число тактов] [число попаданий] [общее число тактов]
0 24960 1 24960
1 6511 1 6511
2 185997 1 185997
3 17881 1 17881
4 3422091812 1 3422091812
5 80 770048 62107103
6 4293 770048 3305833972
7 46430 1 46430
8 76579 1 76579

т.е. больше всего времени занимает тело цикла, но в этом цикле большую часть времени уходит на выполнение строки:
CODE
bmp2->Canvas->Pixels[x1+IX0][y1+IY0]=bmp1->Canvas->Pixels[x][y];

это "копирование" занимает 98% всего времени...
через часик будут вариант избавленный от этого недуга.

проект лежит http://georgiestar.pisem.net/rotateimage.zip (вдруг кто нибудь ещё со мной в скорости работы программы захочет посостязаться?)

Отредактировано Георгий — 17/11/2003, 23:56
Мансур
Отправлено: 18.11.2003, 10:06


Не зарегистрирован







Спасибо Георгий за отклик.
Однако помоему мы с тобою в ложной пути. В применении пиксельного варианта. В инете искал. Предлагают применение метода scanline.
если сделаю что либо, скажу. можешь мне по мейлу писать
jmansur@lan.ab.az
Мансур
Отправлено: 18.11.2003, 10:10


Не зарегистрирован







Спасибо Георгий за отклик.
Однако помоему мы с тобою в ложной пути. В применении пиксельного варианта. В инете искал. Предлагают применение метода scanline.
если сделаю что либо скажу. можешь мне по мейлу писать
jmansur@lan.ab.az
Мансур
Отправлено: 18.11.2003, 10:15


Не зарегистрирован







Спасибо Георгий за отклик.
Однако помоему мы с тобою в ложной пути. В применении пиксельного варианта. В инете искал. Предлагают применение метода scanline.
если сделаю что либо скажу. можешь мне по мейлу писать
jmansur@lan.ab.az
Fred
Отправлено: 18.11.2003, 11:29


Ученик-кочегар

Группа: Участник
Сообщений: 19



1. Для ускорения работы следует отказаться от точечного копирования Canvas1->Pixels[][]=Canvas2->Pixels[][]; Вместо этого использовать свойство битмапа ScanLine[].

2. Чтобы не возникали "дырки" нужно использовать обратное преобразование.

CODE

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 // Исходный БитМап.
   Graphics::TBitmap *BmpO = new Graphics::TBitmap();
   BmpO->LoadFromFile("C:\Program Files\Common Files\Borland Shared\Images\Splash\256color\factory.bmp");

 // БитМап с повернутым изображением.
   Graphics::TBitmap *BmpR = new Graphics::TBitmap();
                      BmpR->Height      = 2*BmpO->Height;
                      BmpR->Width       = 2*BmpO->Width;
                      BmpR->PixelFormat = BmpO->PixelFormat;
                      BmpR->Palette     = BmpO->Palette;

   int Ox = BmpO->Width /2;   // x-координата точки поворота.
   int Oy = BmpO->Height/2;   // y-координата точки поворота.
   int Rx = BmpR->Width /2;    // x-координата смещения.
   int Ry = BmpR->Height/2;    // у-координата смещения.

   double A = M_PI/6;              // Угол поворота.
   double R = 1.5;                    // Коэффициент растяжения.
   double cosa = cos(A)/R;
   double sina = sin(A)/R;

   for( int y = 0; y < BmpR->Height; y++ )
   {
     BYTE * ptr = (BYTE *)BmpR->ScanLine[y];

     double ysina = (y-Ry)*sina + Ox;
     double ycosa = (y-Ry)*cosa + Oy;

     for( int x = 0; x < BmpR->Width; x++)
        {
          double x1 = (x-Rx)*cosa + ysina;
         if( x1>=0 && x1< BmpO->Width )
           {
          double y1 = (Rx-x)*sina + ycosa;
         if( y1>=0 && y1< BmpO->Height)
           {
             ptr[x] = ((BYTE *)(BmpO->ScanLine[y1]))[int(x1)];
           }
           }
        }
   }
   Canvas->Draw(0,0,BmpO);
   Canvas->Draw(0,BmpO->Height+5,BmpR);

 delete BmpR;
 delete BmpO;
}


Этот фрагмент не только поворачивает, но и растягивает(сжимает) изображение с коэффициентом R. Работает для изображений с кол-вом цветов не больше 256. Для большего кол-ва цветов нетрудно самому программу доделать.
Fred
Отправлено: 18.11.2003, 11:52


Ученик-кочегар

Группа: Участник
Сообщений: 19



Почему-то в пути к файлу исчезли двойные слеши "\\" :)
Георгий
Отправлено: 19.11.2003, 23:15


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



ну и ###### у меня с телефоном творится — только сейчас заработал
ускорил поворот с 1.5 сек до 0.3, но что написал Fred ещё не смотрел

Fred
Идея использовать scanline меня тоже посетила, но я решил для этих создать свой обьектик, НО Ты меня сделал — у тебя более быстрый код — мой поворачивает тестовую картинку за ~180ms, а твой за ~100ms т.е. почти в 2 раза быстрее.

Кстати можешь доступно объяснить почему у тебя нет "выпадающих" точек?

Проектик, который умеет крутить обоими методами и работать с bmp 8, 16, 24, 32 бит лежит на http://georgiestar.pisem.net/rotateimage.zip
на тот, что приложен к ответу не образайте внимания это не то

Отредактировано Георгий — 20/11/2003, 01:12

User Attached Image Скачать файл
RotateImage.zip


Fred
Отправлено: 20.11.2003, 03:08


Ученик-кочегар

Группа: Участник
Сообщений: 19



Георгий.

Представь прямоугольник p[x,y], который нужно отобразить на прямоугольник P[X,Y], у которого стороны вдвое длиннее. Если применять прямое отображение, как это сделал Мансур, то мы отобразим x*y точек, хотя в прямоугольнике P точек в 4 раза больше. И у нас получится 3*x*y "дырок". Поэтому нужно применять обратное преобразование — для каждой точки прямоугольника P[X,Y] искать образ в прямоугольнике p[x,y]. Аналогичная ситуация происходит и при повороте. Точки исходного прямоугольника могут отображаться "мимо" некоторых точек прямоугольника, на которое происходит отображение. Поэтому, чтобы такого не происходило, нужно для каждой точки прямоугольника-образа искать соответствующую точку на исходном прямоугольнике.

Надеюсь объяснение понятное получилось. Если нет — попробую еще раз smile.gif

Отредактировано Fred — 20/11/2003, 09:40
Георгий
Отправлено: 20.11.2003, 09:40


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



Fred
Спасибо — понял. Замечательное решение smile.gif
Мансур
Отправлено: 26.11.2003, 16:12


Не зарегистрирован







Я использовал этот способ сканлайн даже глубоко не вникая в суть. Как показано ниже. Полный кайф гак говорят smile.gif
Устраивает полностью.
URL http://www.efg2.com/Lab/ImageProcessing/Da...ateScanline.ZIP

Вернуться в Вопросы программирования в C++Builder