Модераторы: Snowy, Alexeis, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> опять эти повороты 
:(
    Опции темы
CompWorm
Дата 20.12.2008, 23:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



нет, нет! у меня не совсем обычный поворот изображения. 
я уже понял что нормальных алгоритмов поворота не найти, поэтому вопрос немного в другом.
(но если есть у вас хороший алгоритм - буду рад заюзать smile )

вот надо повернуть огромное изображение и часть его отрисовать в небольшом имидже.
помогите придумать шустрый алгоритм.  smile 

пока придумал следующую оптимизацию, коей не сильно доволен.
user posted image

итак, 
- грузим большое изображение в битмап
- из большого изображения BitBlt'им в битмап1 кусок вдвое больше имиджа, на который выводим.
- поворачиваем битмап1  и результат пишем в битмап2
- из повернутого в битмап2 изображения, которое все еще вдвое больше имиджа, 
BitBlt'им кусок из середины, равный имиджу в этот имидж.
- повторить  smile 

вот прога
http://www.filehoster.ru/files/bx3882
поворот взял конечно чужой. он в модуле Rotate...

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

кто может подсказать алгоритм быстрее моего дам плюс  smile 


--------------------
PM MAIL   Вверх
AntonN
Дата 21.12.2008, 00:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 491
Регистрация: 8.8.2006

Репутация: 7
Всего: 18



Вырезать из большого центр, размеры нетрудно посчитать (диагонали области вывода будут габаритными), сохраняем в буфере (единожды, а не как в примере).
На подопытный битмап наносим повернутое изображение из буфера, выводим в область вывода.
Вот чуть оптимизированный вариант, примерно 10-15% выигрыша smile
Код

rocedure CopyRotateTransparentBrush(_B_in,_B_out: TBitmap; _x,_y,centerX,centerY:integer; _angle: Double);
var cosRadians,_Rad,sinRadians : Double;
  x,y,x_cor,y_cor,x_corS,y_corS,inXOut,inXPr,inXRotated,inYOut,inYPr,inYRotated: Integer;
  RowOut, RowIn: PRGBAArray;
  _w,_h:integer;
begin
  _Rad:=_angle; sinRadians:=Sin(_Rad); cosRadians:=Cos(_Rad);
  _w:=_B_in.Width;  _h:=_B_in.Height;
  if _x<0 then x_corS:=abs(_x) else x_corS:=0;
  if _y<0 then y_corS:=abs(_y) else y_corS:=0;
  if (_x+_w)>_B_out.Width then x_cor:=_x+_w-_B_out.Width else x_cor:=0;
  if (_y+_h)>_B_out.Height then y_cor:=_y+_h-_B_out.Height else y_cor:=0;
  for x:=_h-1-y_cor downto y_corS do begin
    RowIn:=_B_out.Scanline[x+_y]; inXPr:=2*(x-centerY)+1;
    for y:=_w-1-x_cor downto x_corS do begin
      inYPr:=2*(y-centerX)+1;
      inYRotated:=Round(inYPr*CosRadians-inXPr*sinRadians);
      inXRotated:=Round(inYPr*sinRadians+inXPr*cosRadians);
      inYOut:=(inYRotated-1) div 2 + centerX; inXOut:=(inXRotated-1) div 2 + centerY;
      if (inYOut>=0)and(inYOut<=_w-1)and
      (inXOut>=0)and(inXOut<=_h-1) then begin
        RowOut:=_B_in.Scanline[inXOut];
        RowIn[y+_x] := RowOut[inYOut];
      end;
    end;
  end;
end;


Для более серьезного ускорения нужно уже бросать scanline и работать с памятью напрямую (scanline годится для последовательной выборки строк, а не как в данном случае - вразнобой, хоть и в 7 раз быстрее чем с pixels[] smile ). Но там и поковыряться придется... Зато даже просто заменив массивом Tbitmap в данном примере скорость будет раз в 5 больше, это даже без оптимизации до асма.


--------------------
user posted image
PM MAIL WWW   Вверх
CompWorm
Дата 21.12.2008, 13:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



благодарю, лови плюс. 
поместил в отдельный тред и наступило счастье (тут)

модификации к _scanline это конечно хорошо, но ты упомянул работу с памятью (я так надеюсь, без директ-ыхс)...
можно попросить тебя ответить более развернуто?
какая именно память, ссылки на статьи и исходники дабы я мог обучиться этому кудесничеству...
 smile 




--------------------
PM MAIL   Вверх
AntonN
Дата 21.12.2008, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 491
Регистрация: 8.8.2006

Репутация: 7
Всего: 18



Цитата

можно попросить тебя ответить более развернуто?

могу скинуть примерчик, но попозже, работаю smile
Если описательно:
Создается обычный динамический массив, array of dword (4 байта, как раз ARGB). Массив линейный даже можно.

Код
const
  MaxBTCount = MaxInt div SizeOf(dword);
type
  BTElement = dword;
  TBTArray = array[0..MaxBTCount-1] of BTElement;

var P: ^TBTArray;


Выделяется его ровно на кол-во пикселей в нашей картинке и битмап в него загоняется:
Код

procedure load_from_bitmap(bitmap:tbitmap);
var x,y: Integer;  Row24:PRGBArray; Row32:PRGBAArray; b:byte;
begin
 P:=AllocMem(bitmap.width*bitmap.height*SizeOf(BTElement));
 if(bitmap.PixelFormat=pf32bit) then begin
   for Y:=0 to bitmap.Height-1 do begin
    Row32:=bitmap.ScanLine[y];
     for x:=0 to bitmap.Width-1 do
        P^[ y*DIBWidth+x ]:=(Row32[x].rgbRed or (Row32[x].rgbGreen shl 8) or (Row32[x].rgbBlue shl 16) or (Row32[x].rgbReserved shl 24));
  end;
 end else begin
  bitmap.PixelFormat:=pf24bit;
  for Y:=0 to bitmap.Height-1 do begin
   Row24:=bitmap.ScanLine[y];
    for x:=0 to bitmap.Width-1 do begin
      if((Row24[x].rgbtRed=255) and (Row24[x].rgbtGreen=0) and (Row24[x].rgbtBlue=0)) then
        b:=0 else
        b:=255;
        P^[ y*DIBWidth+x ]:=(Row24[x].rgbtRed or (Row24[x].rgbtGreen shl 8) or (Row24[x].rgbtBlue shl 16) or (b shl 24));
    end;
  end;
 end;
end;


Все, теперь в памяти кусок данных, доступ к "пикселям":
Код
function GetPixel_unsafe( x, y: integer): TColor;
begin
  result:=TColor(pointer(DWORD(@P^[0])+DIBSize*y+x*4)^);
end;

procedure SetPixel_unsafe(x, y: integer; col: TColor);
begin
  TColor(pointer(DWORD(@P^[0])+DIBSize*y+x*4)^):=col;
end;


Используем эти функции вместо соотвествующих в функции поворота, скорость доступа будет гораздо быстрее.
Ну а в конце сохраняем массив обратно в битмап и выводим его:

Код
procedure Save_to_bitmap(Bt:Tbitmap);
var x,y:Integer; Row32:PRGBAArray; fd:dword;
begin
  Bt.PixelFormat:=pf32bit;
  Bt.Width:=DIBWidth;
  Bt.Height:=DIBHeight;
   for Y:=0 to Bt.Height-1 do begin
     Row32:=Bt.ScanLine[y];
     for x:=0 to Bt.Width-1 do begin
       fd:=P^[ y*DIBWidth+x ];
       Row32[x].rgbBlue:=Byte(fd shr 16);
       Row32[x].rgbGreen:=Byte(fd shr 8);
       Row32[x].rgbRed:=Byte(fd);
       Row32[x].rgbReserved:=Byte(fd shr 24);
     end;
   end;
end;


Вообще вся эта мишура тем эффективней, чем больше операций нужно провести над "битмапами". Загрузив исходные картинки в массивы и выгружая лишь один раз результат скорость будет немалая.
Сам такой класс есть в моих танчиках, тут (в самом низу) - http://desksoft.ru/index.php?files&id=3&owner=3 , вроде умеет загружаться и сохраняться в битмап, ну и для самой игры он может быстро рисоваться с альфаканалом и прозрачным цветом друг на друге smile

Функция, такая же как выше, пимерно так выглядела (писал как раз для теста smile ):
Код
procedure TGDEngine.Rotate_slow(BTSourc,BTDest:TBT; _x,_y,centerX,centerY:integer; _angle: Double);
var cosRadians,_Rad,sinRadians : Double;
  x,y,x_cor,y_cor,x_corS,y_corS,inXOut,inXPr,inXRotated,inYOut,inYPr,inYRotated,iil: Integer;
   RowIn: PRGBAArray;
begin
  _Rad:=_angle; sinRadians:=Sin(_Rad); cosRadians:=Cos(_Rad);
  if _x<0 then x_corS:=abs(_x) else x_corS:=0;
  if _y<0 then y_corS:=abs(_y) else y_corS:=0;
  if (_x+BTSourc.DIBWidth)>BTDest.DIBWidth then x_cor:=_x+BTSourc.DIBWidth-BTDest.DIBWidth else x_cor:=0;
  if (_y+BTSourc.DIBHeight)>BTDest.DIBHeight then y_cor:=_y+BTSourc.DIBHeight-BTDest.DIBHeight else y_cor:=0;
  for x:=BTSourc.DIBHeight-1-y_cor downto y_corS do begin
    inXPr:=2*(x-centerY)+1;
    iil:=x*BTSourc.DIBWidth;
    for y:=BTSourc.DIBWidth-1-x_cor downto x_corS do begin
      inYPr:=2*(y-centerX)+1;
      inYRotated:=Round(inYPr*CosRadians-inXPr*sinRadians);
      inXRotated:=Round(inYPr*sinRadians+inXPr*cosRadians);
      inYOut:=(inYRotated-1) div 2 + centerX; inXOut:=(inXRotated-1) div 2 + centerY;
      if (inYOut>=0)and(inYOut<=BTSourc.DIBWidth-1)and (inXOut>=0)and(inXOut<=BTSourc.DIBHeight-1) then
         BTDest.P^[ iil+y ]:=BTSourc.P^[ inXOut*BTSourc.DIBWidth+inYOut ];
    end;
  end;
end;

(т.е. создаешь два TBT, один исходныик, второй буферный, поворачиваешь исходник на буфер и буфер перегоняешь в битмап, битмап рисуешь на контроле).

Вот smile


--------------------
user posted image
PM MAIL WWW   Вверх
AntonN
Дата 22.12.2008, 00:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 491
Регистрация: 8.8.2006

Репутация: 7
Всего: 18



ну вот, немножко тестовsmile
canvas.pixel - 20,66 сек, fpt ~5
scanline - 5,43 сек, fps ~18
"массив" - 0,26 сек (с выводом в tbitmap в каждом кадре 0,28-0,29), fps~384

в каждом тесте поворачивалась картинка в цикле 100, соотношение скоростей налицо smile
конечно зависимость от процессора, но скорость явно разная smile

сам тест с классом-"псевдобитмапом" - http://desksoft.ru/index.php?downloads=att...ents&id=123 (190кб)


--------------------
user posted image
PM MAIL WWW   Вверх
CompWorm
Дата 22.12.2008, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



любопытно...

действий действительно надо делать много. зачастую в приемник надо вывести десяток крупных наложенных друг на друга повернутых картинок в 10мсек. 
полагаю, тут как раз идея с массивами должна сильно помочь.

спасибо, этого материала мне хватит поразвлекаться на неделю  smile 


--------------------
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Звук, графика и видео"
Girder
Snowy
Alexeis

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

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

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • По вопросам разработки игр стоит заглянуть сюда

FAQ раздела лежит здесь!


Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Girder, Snowy.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Звук, графика и видео | Следующая тема »


 




[ Время генерации скрипта: 0.0705 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.