Мансур |
Отправлено: 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
|
|
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]. Аналогичная ситуация происходит и при повороте. Точки исходного прямоугольника могут отображаться "мимо" некоторых точек прямоугольника, на которое происходит отображение. Поэтому, чтобы такого не происходило, нужно для каждой точки прямоугольника-образа искать соответствующую точку на исходном прямоугольнике.
Надеюсь объяснение понятное получилось. Если нет — попробую еще раз
Отредактировано Fred — 20/11/2003, 09:40 |
|
Георгий |
Отправлено: 20.11.2003, 09:40 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
Fred
Спасибо — понял. Замечательное решение |
|
Мансур |
Отправлено: 26.11.2003, 16:12 |
|
Не зарегистрирован
|
Я использовал этот способ сканлайн даже глубоко не вникая в суть. Как показано ниже. Полный кайф гак говорят
Устраивает полностью.
URL http://www.efg2.com/Lab/ImageProcessing/Da...ateScanline.ZIP |
|