void __fastcall TForm1::Button1Click(TObject *Sender)
{
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
TColor temp;
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int b;
for(int a=-100;a<Image1->Picture->Width;a+=5)
{
b=0;
for(int i=a;i<a+100;i++)
{
for (int j=0;j<Image1->Picture->Height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+50*sin(M_PI*b/100)];
}
b++;
}
Image1->Refresh();
Sleep(10);
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
}
}
Оптимизация кода
Здравствуйте, уважаемые. У меня есть программа, которая загружает изображение в компонент TImage и потом через канву делает анимацию "волны" над этим изображением. Но работает алгоритм очень медленно. Помогите, пожалуйста, оптимизировать код. Скриншот работы программы приведён ниже. Заранее спасибо!
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
TColor temp;
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int b;
[COLOR="Red"]int imagen_widht = Image1->Picture->Width;
int imagen_height = Image1->Picture->Height;
float pi_sot = M_PI/100;
int offset;[/COLOR]
for(int a(-100);a<imagen_widht;a+=5)
{
b=0;
for(int i(a);i<a+100;i++)
{
[COLOR="Red"]offset = 50*int(sin(pi_sot*b));[/COLOR]
for (int j=0;j<imagen_height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+offset];
}
++b;
}
Image1->Refresh();
Sleep(10);
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
}
}
{
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
TColor temp;
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int b;
[COLOR="Red"]int imagen_widht = Image1->Picture->Width;
int imagen_height = Image1->Picture->Height;
float pi_sot = M_PI/100;
int offset;[/COLOR]
for(int a(-100);a<imagen_widht;a+=5)
{
b=0;
for(int i(a);i<a+100;i++)
{
[COLOR="Red"]offset = 50*int(sin(pi_sot*b));[/COLOR]
for (int j=0;j<imagen_height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+offset];
}
++b;
}
Image1->Refresh();
Sleep(10);
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
}
}
мог опечататься. еще можно отправить все это дело в отдельный поток.
Цитата:
50*sin(M_PI*b/100)
а нельзя ли заранее рассчитать весь массив значений синусов, которые нужны? и потом просто подставлять нужное значение из массива?
немного набросаю...
Код:
float pi_sot = M_PI/100;
float sin_mas[100];//b у нас изменяется от 0 до 100 же?
for(int i = 0;i < 100; ++i)
sin_mas = 50*sin(pi_sot*i/100);
...
...
b=0;
for(int i=a;i<a+100;i++)
{
for (int j=0;j<Image1->Picture->Height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+sin_mas];
}
b++;
}
float sin_mas[100];//b у нас изменяется от 0 до 100 же?
for(int i = 0;i < 100; ++i)
sin_mas = 50*sin(pi_sot*i/100);
...
...
b=0;
for(int i=a;i<a+100;i++)
{
for (int j=0;j<Image1->Picture->Height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+sin_mas];
}
b++;
}
таким образом будет всего 100 вычислений синусов, вместо
for(int a(-100);a<imagen_widht;a+=5)*for(int i=a;i<a+100;i++) //лень считать сколько раз он тут подсчитается
В любом случае больше всего "тормозит" алгоритм обращение к Pixels. Вместо Pixels лучше использовать ScanLine.
Цитата: Norgat
а нельзя ли заранее рассчитать весь массив значений синусов, которые нужны? и потом просто подставлять нужное значение из массива?
можно, но это будет не гибко, бо будет только для конкретного размера изображения, да и размер массива то не хилый получается.
Кроме этого лучше один раз загрузить картинку в память и манипуляции производить над ее клоном, который и отображать на Image, но я бы не пользовался компонентом и руками ее отрисовывал.
Цитата: Artem_3A
можно, но это будет не гибко, бо будет только для конкретного размера изображения, да и размер массива то не хилый получается.
ну в примере всего 100 значений синуса нужно...
Код:
b=0;
for(int i(a);i<a+100;i++){... ++b;}
for(int i(a);i<a+100;i++){... ++b;}
как бы от размера картинки там выбор a зависел, а не кол-во проходов цикла, где меняется b.
тогда конечный резалт.
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
TColor temp;
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int b;
int imagen_widht = Image1->Picture->Width;
int imagen_height = Image1->Picture->Height;
float pi_sot = M_PI/100;
int offset[100];
int b;
int temp_size;
for(b = 0; b<100; b++)
offset = 50*int(sin(pi_sot*b));
for(int a(-100);a<imagen_widht;a+=5)
{
temp_size = a + 100;
for(int i(a);i<temp_size;i++)
{
b = 0;
for (int j=0;j<imagen_height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+offset];
}
++b;
}
Image1->Refresh();
Sleep(10);
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
}
}
{
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
TColor temp;
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int b;
int imagen_widht = Image1->Picture->Width;
int imagen_height = Image1->Picture->Height;
float pi_sot = M_PI/100;
int offset[100];
int b;
int temp_size;
for(b = 0; b<100; b++)
offset = 50*int(sin(pi_sot*b));
for(int a(-100);a<imagen_widht;a+=5)
{
temp_size = a + 100;
for(int i(a);i<temp_size;i++)
{
b = 0;
for (int j=0;j<imagen_height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+offset];
}
++b;
}
Image1->Refresh();
Sleep(10);
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
}
}
топикавтор - проверяй, бо мы тут сие на коленке писали.
Цитата: Norgat
ну в примере всего 100 значений синуса нужно...
Верно, но как я уже писал, проблема не только в них.
Цитата: hardcase
В любом случае больше всего "тормозит" алгоритм обращение к Pixels. Вместо Pixels лучше использовать ScanLine.
есть смутная мысль, что там все будет оптимизировано компилятором.
Цитата: Artem_3A
есть смутная мысль, что там все будет оптимизировано компилятором.
Есть смутная мысль, что Хардкейз с этим сам неоднократно сталкивался. ;)
Цитата: hardcase
Есть смутная мысль, что Хардкейз с этим сам неоднократно сталкивался. ;)
Тогда есть смутная мысль, что предыдущая смутная мысль отпадает.:D
Со ScanLine я сейчас разберусь.
Может ещё есть какие-то идеи?
Исправленный код:
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
TColor temp;
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int b;
int imagen_widht = Image1->Picture->Width;
int imagen_height = Image1->Picture->Height;
float pi_sot = M_PI/100;
int offset[100];
for(b = 0; b<100; b++)
offset = 50*sin(pi_sot*b);
for(int a=-100;a<imagen_widht;a+=5)
{
b=0;
for(int i=a;i<a+100;i++)
{
for (int j=0;j<imagen_height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+offset];
}
b++;
}
Image1->Refresh();
Sleep(10);
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
}
}
{
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
TColor temp;
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int b;
int imagen_widht = Image1->Picture->Width;
int imagen_height = Image1->Picture->Height;
float pi_sot = M_PI/100;
int offset[100];
for(b = 0; b<100; b++)
offset = 50*sin(pi_sot*b);
for(int a=-100;a<imagen_widht;a+=5)
{
b=0;
for(int i=a;i<a+100;i++)
{
for (int j=0;j<imagen_height;j++)
{
Image1->Canvas->Pixels[j]=Image1->Canvas->Pixels[j+offset];
}
b++;
}
Image1->Refresh();
Sleep(10);
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
}
}
Код:
Image1->Picture->LoadFromFile("C:\\CONTENT.BMP");
вот это очень узкое место. на каждой итерации с жестяка грузим в память картинку. в билдере я думаю есть какой нить клас тип TPicture(я как бы на билдере не очень кодил, так что в его библиотеках не особо), так вот, загрузить в него картинку и постоянно хранить. когда нужен будет новый экземпляр, то просто копировать ее. при чем все манипуляции по созданию волны лучше производить именно в этом классе, а не в компоненте формы.
так же вместо слипа используйте таймер.
ЗЫ: а вообще обо всем этом писал уважаемый hardcase ниже, читайте внимательней.