Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Оптимизация кода


Страницы:   1 2 3 4 5 6 7 8 9 10 11

Вова ©   (2013-06-25 20:17:00) 

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


function almostEqual(a, b: byte): Boolean;
begin
 if ABS(a - b) < 10 then
   result := true
 else
   result := false;
end;

Function ConvertColorToRGBColorMap(color: LongInt; ColSel: String = 'None')
 : TColorWithName;
var
 RGBV: trgbcolor;
begin

 RGBV.red := color;
 RGBV.green := color shr 8;
 RGBV.blue := color shr 16;

 with RGBV do

   if almostEqual(red, green) and almostEqual(red, blue) and
     almostEqual(blue, green) then // тогда это серый или черный или белый
   begin
     if almostEqual(red, 255) then // белый
     begin
       result.color := RGB(255, 255, 255);
       result.Name := 'White';
     end
     else if red > 120 then
     begin
       result.color := RGB(190, 190, 190);
       result.Name := 'LightGray';
     end
     else if (red > 92) then // темно серый
     begin
       result.color := RGB(100, 100, 100);
       result.Name := 'DarkGray';
     end
     else
     begin
       result.color := RGB(0, 0, 0);
       result.Name := 'Black';
     end // черный
   end
   else
   begin
     if (red < green) and (red < blue) and almostEqual(green, blue) and
       (blue > 130) then
     begin
       result.color := RGB(0, 0, 255);
       result.Name := 'Blue';
     end // result:= rgb(0,255,255)//голубой
     else if (green < red) and (green < blue) and almostEqual(red, blue) and
       (red > 130) then
     begin
       result.color := RGB(255, 0, 255);
       result.Name := 'Pink';
     end // розовый
     else if (blue < green) and (blue < red) and almostEqual(green, red) and
       (green > 130) then
     begin
       result.color := RGB(255, 255, 0);
       result.Name := 'Yellow';
     end // желтый
     else if (red > green) and (red > blue) and (red > 130) then
     begin
       result.color := RGB(255, 0, 0);
       result.Name := 'Red';
     end // красный
     else if (blue > green) and (blue > red) and (blue > 130) then
     begin
       result.color := RGB(0, 0, 255);
       result.Name := 'Blue';
     end // синий
     else if (green > blue) and (green > red) and (green > 130) then
     begin
       result.color := RGB(0, 255, 0);
       result.Name := 'Green';
     end // зеленый
     else
     begin
       result.color := RGB(0, 0, 0);
       result.Name := 'Black';
     end
   end;

   if not (ColSel = 'None') then
     if not (ColSel = Result.Name) then
     begin
       result.color := RGB(255, 255, 255);
       result.Name := 'White'; //Если выборка только по одному цвету, то
       //все остальные цвета переводим в белый
     end
     else
     begin
       result.color := RGB(0, 0, 0);
       result.Name := 'Black'; //Если выборка только по одному цвету, то
       //этот цвет переводим в черный
     end

end;


ProgRAMmer Dimonych   (2013-09-02 21:22:00) [1]

> забоялся делать много потоков (таки может и зря?) и только
> несколько процессов туда поместил

Осторожнее с понятиями: таки слово процесс уже зарезервировано для обозначения кой-чего другого, чем кусок кода, и в том значении как раз несколько потоков в процессе, а не наоборот :)


Sha   (2013-09-02 09:41:00) [2]

1. А что в книжках про это пишут?
2. Новые обсуждения лучше затевать в новых ветках.
3. А про коней в вакууме лучше в разделе "Прочее"


Вова   (2013-09-02 01:58:00) [3]

кстати хорошо или плохо если создать много потоков? ну там например 100? )) вообщем дело в том, что когда все делается в основном потоке, то делается это последовательно, и нельзя какое то звено тормознуть, т.к. этим ты тормознешь и тех кто идет следом. В то же время когда это делается в потоке, то процедура выполняется и ставится на паузу - т.е. во втором случае во первых никто не ждет пока процесс себя выполнит, т.к. он сам обновляет результат с необходимой переодичностью, во вторых процессор не шарашит как оголделый по 20 раз одно итоже и следовательно меньше нагружается. Я б даже сказал по опыту разница  загрузки проца огромна. Хотя с другой стороны цикл основного процесса все равно будет носится и грузить проц. А во вторых в одно время выполняется только одна из веток программы, т.е. часть процедур может минут по 20 не использоваться, а если они в потоке будут крутиться, то постоянно, т.к. нужны они становятся по событию, а не по таймеру. вообщем сколько потоков юзать оптимально? особенно учитывая, что желательный режим работы на одном ядре (виртуальном) процессора?

на данный момент я как то забоялся делать много потоков (таки может и зря?) и только несколько процессов туда поместил, а остальное в основном кручу. Т.е. класс создается, но не запускается и процедуры выполняются в основном потоке его )


Sha   (2013-08-25 12:30:00) [4]

> Sapersky   (25.08.13 03:26) [205]

вот, оказывается, где талант педагога скрывается )


Sapersky   (2013-08-25 03:39:00) [5]

Строго говоря, таблица в первом и втором вариантах не of Integer, а of TRGB из [160], хотя я думаю и так можно сообразить, но кто ж Вову знает...


Sapersky   (2013-08-25 03:26:00) [6]


> Вова   (24.08.13 21:18) [203]

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

Нужно преобразовать один набор цветов в другой с помощью таблицы. Вариант в лоб - создаём таблицу для всех возможных цветов: ColorMap = array [0..255, 0..255, 0..255] of Integer, прописываем в ней результирующие цвета и выполняем простую как мычание операцию:
Color = ColorMap[Color.r, Color.g, Color.b]
Всё работает, но размер таблицы получается 64 мб, как-то многовато.

Далее, наша операция - огрубление цветов, поэтому нам не очень-то нужны тонкие оттенки. Создадим таблицу не для каждого возможного цвета, а с шагом 16, 256 / 16 = 16 значений на канал.
ColorMap = array [0..15, 0..15, 0..15] of Integer.
Соответственно, чтобы выбрать из такой таблицы, цвета нужно делить на 16:
Color = ColorMap[Color.r div 16 , Color.g div 16, Color.b div 16].
Деление на 16 - это на самом деле и есть "взять старшие биты", точнее, "сдвинуть старшие биты на место младших", фактически компилятор заменяет его на shr 4. Можно заменить самостоятельно, вроде так оптимальнее:
Color = ColorMap[Color.r shr 4, Color.g shr 4, Color.b shr 4].

Если оставить всё именно так - о битах можно не думать. И это неплохой вариант, памяти много не жрёт и по скорости гораздо лучше расчёта на лету. Но если оптимизировать до упора, нужно заменить трёхмерный массив на одномерный:
Color = ColorMap[(Color.r div 16) * 16*16 + (Color.g div 16) * 16 + (Color.b div 16)].
и убрать обращения к отдельным компонентам Color, учитывая, что:
Color.r = Color shr 16 and $FF
Color.g = Color shr 8 and $FF
Color.b = Color and $FF
Подробно мне расписывать не очень хочется, но в общем, в результате всех подстановок и упрощений мы должны получить строчку из [175]. У Sha ещё чуть заковыристее, но принцип тот же.

Вот для этого последнего уровня оптимизации и нужно понимание битовых операций. А так, таблица она и есть таблица, с какими заклинаниями её ни вызывай.


Плохиш   (2013-08-25 00:31:00) [7]

Зачем оно тебе, это программирование? Тебе всë-равно не интересно.

PS. Вместо обид остановись, успокойся и подумай, что ты хочешь сделать.


Вова   (2013-08-24 21:18:00) [8]

равно как и в [119]


> Каждую из них усекаем до старших 4х битов:
>  i:=i and $F0F0F0;


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


> Формируем число от 0 до 16*16*16-1 - будущий индекс цвета
> в таблице:
>  i:=(i shr 12 and $F) + (i and $F0) + (i shr 12 and $F00);
>


ну тут тоже все понятно ваще...и так далее )


Sha   (2013-08-24 21:17:00) [9]

значит, нам придется поработать над собой )


Вова   (2013-08-24 21:07:00) [10]

если цель программы научить кого то чему то, то там в изобилии должны быть комментарии объясняющие процесс. Ибо в 100 раз повторяю я не понимаю что происходит в [81]. Благодаря тем же причинам я не понимаю, что написано в твоем блоге, который я честно пытался читать, потому что там также стены кода в которых можно что либо понять, только если ты итак уже это знал.

имеет смысл учить на языке понятном обучаемому. Так что я выучил то что сумел понять.


Sha   (2013-08-24 19:51:00) [11]

> ведь никто ж не ценит твоего времени и не показывает как

Пример чтения четырех пикселей за три операции в приведен [81].
Там же показано, как развернуть цикл и сэкономить на проверках.
В [12] и [119] разжевано кеширование результата функции.
По ходу обсуждения немного разобраны битовые операции.
В [193] в 100й раз повторено, что *ВСЯ* твоя задача решается
за один проход без предварительного копирования, переворотов и т.п.

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


Вова   (2013-08-24 19:43:00) [12]

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


Вова   (2013-08-24 19:39:00) [13]

а нет....это не из за этого...


Вова   (2013-08-24 19:36:00) [14]

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

 m^ := (Mass + (i shr 12 and $F0F or i and $F0))^;


Вова   (2013-08-24 19:29:00) [15]


Procedure Convert(Start,Stop:pInteger;Width:integer;m:pByte;Mass: TColorMapByte);
var
 count,i:Integer;
begin
 count := Width;
 repeat
   repeat
   i := Start^;
   m^ := Mass[i shr 12 and $F0F or i and $F0];
   inc(Start);
   inc(m);
   dec(count);
   until count = 0;
   count := Width;
   dec(Start,Width*2);
 until Start = Stop;
end;

function ConvertBmpToRGBColorMapM(tBmp: Tbitmap; var M: TMass;
 Mass: TColorMapByte): Boolean;
var
 Start, Stop: pInteger;
begin
 //tbmp.SaveToFile('C:\yui.bmp');
 Start := tBmp.ScanLine[0];
 dec(Start,tBmp.Width);
 Stop  := tBmp.ScanLine[tBmp.Height - 1];
 inc(Stop,tBmp.Width);
 Convert(Start,Stop,tBmp.Width,@M.Mass[0],Mass);
 Result := true;
end;


я вкурил как указатель на массив передать, 3 миллисекунды, вместо 4.


Sha   (2013-08-24 18:49:00) [16]

> оке, за счет чего тогда в 2 раз медленней?

за счет чего угодно, если интересно, приведи здесь оба кода, посмотрим


Вова   (2013-08-24 17:53:00) [17]

1) однобайтный массив еще нужно получить в коде вверху я это и делаю.
2) несомневаюсь, но как перевернуть картинку в 1 проход я не знаю, и я не могу сделать то чего не знаю как сделать )
3) может и бред, но у меня не хватает воображения чтобы потом с отзеркаленым изображением работать (даже если его по вертикали развернуть легко, но еще нужно по x отразить).  тем более что поиск должен идти сверху вниз и слева направо, т.е. если не перевернуть его тут, то потом при поиске все равно нужно извращаться. Что у меня и не получилось )
4) оке, за счет чего тогда в 2 раз медленней? без разворота будет 3-3.5 миллисекунды
5) все стоит времени и не всегда результат окупает затраты. Может и научусь, так ведь никто ж не ценит твоего времени и не показывает как. 20 минут гугла ничему мну не научили )


Sha   (2013-08-24 17:41:00) [18]

> Вова   (24.08.13 16:00) [187], [188]

1. правильная работа массивом 1-байтных элементов будет заметно быстрее
2. все можно сделать за один проход
3. перевороты изображения - очевидный бред
4. рассуждения про скорость позиционирования - самоуспокаивающий бред
5. то, что ты не умеешь - не аргумент, учись


Вова   (2013-08-24 17:39:00) [19]

ощема, вот так вот 4 миллисекунды, вместо 2х когда конвертишь сам битмап. В указателях слаб, поэтому невкурил как вместо m:TArrInt указатель на него передать и указателем по массиву бежать, так что ввел num (
Procedure Convert(Start,Stop:pInteger;Width:integer;m:TArrInt;Mass: TColorMapByte);
var
 count,i,num:Integer;
begin
 count := Width;
 num   := 0;
 repeat
   repeat
   i := Start^;
   m[num] := Mass[i shr 12 and $F0F or i and $F0];
   inc(Start);
   inc(num);
   dec(count);
   until count = 0;
   count := Width;
   dec(Start,Width*2);
 until Start = Stop;
end;

function ConvertBmpToRGBColorMapM(tBmp: Tbitmap; var M: TMass;
 Mass: TColorMapByte): Boolean;
var
 Start, Stop: pInteger;
begin
 //tbmp.SaveToFile('C:\yui.bmp');
 Start := tBmp.ScanLine[0];
 dec(Start,tBmp.Width);
 Stop  := tBmp.ScanLine[tBmp.Height - 1];
 inc(Stop,tBmp.Width);
 Convert(Start,Stop,tBmp.Width,M.Mass,Mass);
 Result := true;
end;


Вова   (2013-08-24 16:40:00) [20]

*т.е. для неперевернутого....ну вообщем для такого как в битмапе ))


Страницы:   1 2 3 4 5 6 7 8 9 10 11

Наверх

Титульная страница Поиск, карта сайта Написать письмо