Текущий архив: 2014.07.06;
Скачать: CL | DM;
Вниз
Оптимизация кода Найти похожие ветки
← →
Вова (2013-06-25 20:17) [0]Есть процедура задачей которой является приведения пикселя любого цвета к цвету одного из диапазонов. Но скорость ее работы огорчает меня, можно ли ее как нибудь ускорить?
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;
← →
Sha © (2013-06-25 21:22) [1]этот алгоритм был дан свыше сразу в таком виде, или ему предшествовало какое-то описание?
← →
RWolf © (2013-06-25 23:14) [2]
> можно ли ее как нибудь ускорить?
выкинуть всё, связанное со строками.
возвращать только получившийся цвет или код диапазона.
← →
Вова (2013-06-26 06:09) [3]он не был дан свыше я его накалякал сам )
а что тут описывать?
смотрим в каком диапазоне цвет и приводим цвет к значению конца этого диапазона
← →
Sha © (2013-06-26 08:06) [4]> я его накалякал сам )
О том, и речь, что одному описанию могут соответствовать несколько разных алгоритмов.
И совершенно непонятно, почему надо оптимизировать именно этот вариант алгоритма.
Не говоря уже о том, что можно выбрать другие константы и правила сравнения.
И, наконец, что-то там с голубым напутано.
← →
Вова (2013-06-26 09:50) [5]эм, а какой вариант оптимизирвать? у меня только один есть...
голубой поначалу был голубым, но потом я решил что он тоже будет синим, так что так и задумано
можно изменить через tbmp.PixelFormat := pf8bit; количество цветов но все же это не то что нужно, картинка после этого выглядит неудобо варимой, а свой алгоритм можно еще и поднастроить под конкретную ситуацию (ну вот как я захотел и убрал голубой)
← →
Sha © (2013-06-26 09:54) [6]> эм, а какой вариант оптимизирвать? у меня только один есть...
ты б задачу описал, может другие варианты и появились бы )
а то получается, спрашиваешь, в мешке какого цвета лучше бегать стометровку
← →
Sha © (2013-06-26 10:20) [7]например, вот такой вариант:
Color:=ColorMap[Color shr 12 and $F0F or Color and $F0];
← →
Вова (2013-06-26 10:37) [8]Задача взять TBitmap 24 битный и поменять в нем цвета каждого пикселя. т.e. в картинке все цвета должны преобразоваться к: Белому, Светлосерому, Темносерому,черному, синему,красному, зеленому, розовому, желтому.
делается это для того чтобы четко выделить объекты на картинке, например, буквы светлосерые, но на 24 битном изображении это куча разных значений цветов. пороговое преобразование работает в данном случае ненадежно, т.к. яркость фона непостоянна (т.е. определять границы объектов по разцице яркостей), но зато оно работает в 2 раза быстрее этого алгоритма ( несмотря на то что я всю картинку раз 5 прохожу пороговым, а этим всего 1 )
т.е. я могу сказать что после фильтрации на картинке должен остаться только светлосерый цвет и искать после этого текст отбросив все остальное.
понятно, что на разных картинках диапазоны цветов приводящие к желаемому результату могут быть разные, поэтому желательно очень, чтобы их можно было настраивать.
как то так.
← →
Вова (2013-06-26 10:44) [9]
> например, вот такой вариант:
>
> Color:=ColorMap[Color shr 12 and $F0F or Color and $F0];
>
вау, я ничо не понял. где нибудь есть букварь по такому алгоритму?
← →
Sha © (2013-06-26 10:57) [10]Количество градаций каждой составляющей цвета уменьшаем до 16, оставляя по 4 старших бита от каждой.
Итого получаем 16*16*16 разных цветов. Будем использовать их как индекс в массиве.
Где-то в самом начале программы для инициализируем массив результирующих цветов.
Осталось вычислить индекс входного цвета в нашем массиве и извлечь оттуда результат.
← →
Sha © (2013-06-26 11:09) [11]Инициализация выглядит так:
for i:=0 to 15 do for j:=0 to 15 do for k:=0 to 15 do ColorMap[i*256+16*k+j]:=YourSuperFunc(i*256*256+j*256+k);
← →
Sha © (2013-06-26 11:11) [12]Нет не так, а вот так:
for i:=0 to 15 do for j:=0 to 15 do for k:=0 to 15 do ColorMap[i*256+16*k+j]:=YourSuperFunc((i*256*256+j*256+k)*16);
← →
han_malign (2013-06-27 09:34) [13]
> на разных картинках диапазоны цветов приводящие к желаемому результату могут быть разные
- для уменьшения глубины цвета(квантизации) - используется обычно октантное дерево...
У Фень Юаня есть есть описание алгоритма, и здесь -
http://www.efg2.com/Lab/Graphics/Colors/ShowDemoOne.htm
← →
Sha © (2013-06-27 09:58) [14]в варианте [7,12] перенастройка выполняется аналогично инициализации,
только производится вызов другой YourSuperFunc2 или той же, но с другими параметрами
← →
Sapersky (2013-06-27 11:26) [15]пороговое преобразование работает в данном случае ненадежно, т.к. яркость фона непостоянна
http://locv.ru/wiki/5.7.1_Адаптивное_пороговое_преобразование
← →
Jeer © (2013-06-27 12:33) [16]Да, адаптивное - рулит.
Когда-то было надо, сделал свой вариант:
Константный threshold:
http://s018.radikal.ru/i503/1306/11/a134e2eddde4.jpg
Адаптивный threshold:
http://s14.radikal.ru/i187/1306/2a/8325f2f04dd5.jpg
← →
Вова (2013-06-27 14:49) [17]ща сделал как Sha написал - скорость стала как у порогового, может даж немного быстрее. if then - конкретно тормозят, даже если одно условие вставить то уже +30 милисекунд на картинку (
← →
Вова (2013-06-28 13:28) [18]эх, только вот обнаружилось, что белого при такой инициализации нет в массиве (
Во всяком случае цвет 255 255 255 получается в результате светло серым.
← →
Вова (2013-06-28 14:05) [19]Вообщем после преобразования такого Color shr 12 and $F0F or Color and $F0
разбиение на RGB такого вида:
RGBV.red := color;
RGBV.green := color shr 8;
RGBV.blue := color shr 16;
на выходе дает лажу ( как то например белый превращается в красный
беда в том что я в этих сдвигах битов ничего не понимать, помогите.
← →
Вова (2013-06-28 14:38) [20]Color shr 12 and $F0F or Color and $F0 - как это расшифровать, что это значит?)
← →
MBo © (2013-06-28 14:39) [21]>RGBV.red := color;
>RGBV.green := color shr 8;
>RGBV.blue := color shr 16;
После каждой из этих операций наложи маску $FF для выделения млвдшего байта
(color shr 8) and $FF
>я в этих сдвигах битов ничего не понимать
так разберись, пригодится
Вот, например:
http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=838
← →
Sha © (2013-06-28 14:47) [22]ничего этого (разбивать и понимать) не требуется
1. просто объяви таблицу для хранения вычисленных результатов
var
ColorMap: array[0..16*16*16-1] of integer;
2. заранее помести результаты вызова любой своей функции для 4k цветов в таблицу (см.[12])
3. когда требуется, вместо вызова своей функции бери результат из таблицы (см.[7])
← →
Вова (2013-06-28 14:54) [23]
> ничего этого (разбивать и понимать) не требуется1. просто
> объяви таблицу для хранения вычисленных результатовvar
> ColorMap: array[0..16*16*16-1] of integer;2. заранее помести
> результаты вызова любой своей функции для 4k цветов в таблицу
> (см.[12])3. когда требуется, вместо вызова своей функции
> бери результат из таблицы (см.[7])
я так и делал, и обнаружил что в инициализированном массиве белого цвета нет ( а если я ищу в массиве белый цвет, то он мне возвращает светлосерый.
← →
Sha © (2013-06-28 14:55) [24]не верю, код давай
← →
Sha © (2013-06-28 15:06) [25]Максимальный цвет получается при r=g=b=240 т.к. 4 младших бита обнуляются при инициализации. Для этого цвета твоя функция должна вернуть белый.
Или второй способ - установить эти биты при инициализации, например так:
for i:=0 to 15 do for j:=0 to 15 do for k:=0 to 15 do ColorMap[i*256+16*k+j]:=YourSuperFunc((i*16+15)*256*256+(j*16+15)*256+(k*16+15));
← →
Вова (2013-06-28 15:10) [26]
TColorMap = array[0..16*16*16-1] of TColorWithName;
var
ColorMap:TColorMap;
Procedure InitColorMap();
var
i, j, k: byte;
begin
for i := 0 to 15 do
for j := 0 to 15 do
for k := 0 to 15 do
ColorMap[i * 256 + 16 * k + j] := ConvertColorToRGBColorMap
((i * 256 * 256 + j * 256 + k) * 16);
end;
Function FindConvertedColor(color: LongInt; ColSel: String = "None")
: TColorWithName;
begin
result := ColorMap[color shr 12 and $F0F or color and $F0];
if not(ColSel = "None") then
if not(ColSel = result.Name) then
begin
result := ColorMap[0];
end
else
begin
result := ColorMap[Length(ColorMap)-1];
end;
end;
← →
Sha © (2013-06-28 15:17) [27]Последнюю строчку в InitColorMap спиши из [25] - и будет тебе щастье без черного цвета.
Ты специально тормозишь программу???
Выкинь нафиг вторую функцию. Просто бери элемент массива в нужном месте программы.
А уж если когда понадобится название цвета, тогда вызывай хоть черта с рогами.
← →
MBo © (2013-06-28 15:17) [28]Я бы так скобками обложил:
(Color shr 12) and $F0F or Color and $F0
причина - приоритет and выше, чем у shr
или для читабельности (и при паранойе) вообще так:
((Color shr 12) and $F0F) or (Color and $F0)
← →
Sha © (2013-06-28 15:23) [29]> приоритет and выше, чем у shr
у меня вроде одинаковый)
← →
Sha © (2013-06-28 15:34) [30]> Вова (28.06.13 15:10) [26]
В качестве домашнего задания можешь написать инициализацию таблицы для случая ColSel<>"None".
И со сдвигами разберешься и польза для работы опять же.
← →
Sha © (2013-06-28 15:40) [31]> Вова (28.06.13 15:10) [26]
И эта. Не надо хранить имена. Правильное объявление ColorMap в [22].
← →
Вова (2013-06-28 16:04) [32]таки вы уже хотите сказать что лучше 9 массивов забубенить по 4к элементов?
← →
Вова (2013-06-28 16:05) [33]даж 10, 1 универсальный и 9 по штуке на каждый цвет.
← →
Sha © (2013-06-28 16:08) [34]Где?
Лучше 1 массив инициализировать каждый раз, когда надо.
Все твои случаи сводятся к этому.
И все будет просто летать, т.к. вызовов функции при работе с картинками вообще не будет.
← →
Вова (2013-06-28 16:12) [35]да но по сути это
1) видеопоток
2) ищутся разные объекты в разном цвете
← →
Sha © (2013-06-28 16:13) [36]Тогда 10 массивов лучше
← →
Sha © (2013-06-28 16:21) [37]искомый цвет задается не именем, а адресом массива
← →
Sha © (2013-06-28 16:24) [38]и размер элемента массива становится 1 байт (или даже бит - это можно сделать, если размер имеет значение)
← →
MBo © (2013-06-28 16:25) [39]>у меня вроде одинаковый)
:)
Это я, балбес, с прямым углом перепутал (с or, xor)
← →
Вова (2013-06-29 00:08) [40]дауш, то что вызывать сразу из массива, а не из фунции, то это если что то и дало, то я не заметил. а вот когда я убрал текст, производительность выросла в несколько раз.
← →
Вова (2013-06-29 00:12) [41]по сравнению с первоначальными 300-400 милисекунд на картинку 1920x1080 скорость выросла до 30-40 милисекунд, хотя иногда и 15-16 хз почему так )
← →
Sha © (2013-06-29 00:44) [42]наверно, потому, что GetTickCount тикает 1 раз в 15-16 сек
← →
Sha © (2013-06-29 00:51) [43]> Вова (29.06.13 00:08) [40]
> то что вызывать сразу из массива, а не из фунции, то это если что то и дало, то я не заметил
Потому и не заметил, что засекал не время предоления стометровки,
а суммарное время с разминкой перед бегом.
Не стоит делать выводы из неправильно поставленных экспериментов.
← →
Sha © (2013-06-29 00:55) [44]Ты бы свой код полностью показал.
Почему-то кажется, что в нем найдутся еще тормоза.
← →
Вова (2013-06-29 01:42) [45]
TColorMapByte = array[0..16*16*16-1] of byte;
TMassOfColorMap = array[1..9] of TColorMapByte;
//0 - все цвета(не используется)
//1 - красный белый (255), остальное черный
//2 - синий белый
//3 - зеленый белый
//4 - белый белый
//5 - черный белый
//6 - темно -серый
//7 - светло-серый
//8 - желтый
//9 - розовый
var
MassColorMap :TMassOfColorMap;
инициализация
function TextColorToDigit(nameCol: string): byte;
begin
result := 0;
if nameCol = "Red" then
result := 1;
if nameCol = "Blue" then
result := 2;
if nameCol = "Green" then
result := 3;
if nameCol = "White" then
result := 4;
if nameCol = "Black" then
result := 5;
if nameCol = "DarkGray" then
result := 6;
if nameCol = "LightGray" then
result := 7;
if nameCol = "Yellow" then
result := 8;
if nameCol = "Pink" then
result := 9;
end;
function DigitColorToText(nameCol: byte): string;
begin
case nameCol of
1:
result := "Red";
2:
result := "Blue";
3:
result := "Green";
4:
result := "White";
5:
result := "Black";
6:
result := "DarkGray";
7:
result := "LightGray";
8:
result := "Yellow";
9:
result := "Pink";
else
result := "None";
end;
end;
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, 240) 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 (ColSel = result.Name) then
begin
result.color := 255; //картинка инвертирована для дальнейшей обработки
end
else
begin
result.color := 0;
end;
end;
Procedure InitColorMapMass();
var
i, j, k, col: byte;
begin
for col := 1 to 9 do
for i := 0 to 15 do
for j := 0 to 15 do
for k := 0 to 15 do
MassColorMap[col][i * 256 + 16 * k + j] := ConvertColorToRGBColorMap
((i * 256 * 256 + j * 256 + k) * 16,DigitColorToText(col)).color;
// for i:=0 to 15 do for j:=0 to 15 do for k:=0 to 15 do ColorMap[i*256+16*k+j]:=ConvertColorToRGBColorMap((i*16+15)*256*256+(j*16+15)*256+(k*16+15));
end;
собственно процедура, которая перелопачивает все изображение (конвертирует в двух цветное, по сути в 2 яркости):
function ConvertBmpToRGBColorMapM(tBmp: Tbitmap; var M: TMass;
MainColor: string): Boolean;
var
QP: TQuickPixels;
Pixel1: Cardinal;
x: integer;
y: integer;
numCol: byte;
begin
Result := false;
if MainColor = "None" then
exit;
numCol := TextColorToDigit(MainColor);
if numCol = 0 then
exit;
if (tBmp.Height > 2) and (tBmp.Width >= 1) then
begin
tBmp.PixelFormat := pf24bit;
QP := TQuickPixels.Create;
QP.Attach(tBmp);
M := TMass.Create();
M.Xsize := QP.Width;
M.Ysize := QP.Height;
M.size := M.Xsize * M.Ysize;
M.NewMassSize(M.size);
for y := 0 to QP.Height - 1 do
begin
for x := 0 to QP.Width - 1 do
begin
Pixel1 := QP.GetPixels24(x, y);
M.Mass[x + y * M.Xsize] := MassColorMap[numCol]
[Pixel1 shr 12 and $F0F or Pixel1 and $F0];
end;
end;
QP.Free;
Result := true;
end;
end;
← →
Inovet © (2013-06-29 03:57) [46]Так, к слову.
> [45] Вова (29.06.13 01:42)
> if nameCol = "Red" then
> result := 1;
> if nameCol = "Blue" then
> result := 2;
if nameCol = "Red" then
result := 1;
else if nameCol = "Blue" then
result := 2;
else if
...
> [45] Вова (29.06.13 01:42)
> if ABS(a - b) < 10 then
> result := true
> else
> result := false;
result := ABS(a - b) < 10
Зачем повторять это в ConvertColorToRGBColorMap? Я знаю один ответ - чтобы найти приключений. А теперь эту функцию вызвать 100500 раз.
← →
Sha © (2013-06-29 10:14) [47]> Вова (29.06.13 01:42) [45]
Улучшения ConvertBmpToRGBColorMapM, чтобы получить еще одно заметное ускорение:
1. зачем этот оператор
numCol := TextColorToDigit(MainColor);
внутри функции?
У тебя НЕ ДОЛЖНО этого быть нигде, кроме процедур инициализации.
2. зачем нужно изменение PixelFormat?
Ты ДОЛЖЕН уметь обрабатывать любой допустимый формат.
3. зачет тебе
QP: TQuickPixels;
То, как ты применяешь TQuickPixels только создает дополнительные тормоза
Посмотри пример для ScanLine из справки. Его вполне достаточно. И быстрее будет.
Во вложенном цикле (который бежит по пикселам строки) НЕ ДОЛЖНО быть обращений к процедурам.
4. Массив MassColorMap, конечно может быть двумерным, но во вложенном цикле ты ДОЛЖЕН работать с одномерным массивом. Подумай, как это сделать.
5. Ты ДОЛЖЕН выделить двойной цикл обработки изображения (и ничего кроме него) в отдельную процедуру.
← →
Sha © (2013-06-29 10:22) [48]Замечание.
Пункт [47.4] подразумевает об работу с массивом типа
TColorMapByte = array[0..16*16*16-1] of byte;
через указатель на его начало
PColorMapByte= ^TColorMapByte
аналогично тому, как используется ScanLine.
← →
Вова (2013-06-29 11:22) [49]
> 2. зачем нужно изменение PixelFormat?Ты ДОЛЖЕН уметь обрабатывать
> любой допустимый формат.
в купикселях есть общая процедура GetPixel, SetPixel и отдельная на каждый формат. Я с самого начала выбрал 24 вот и мучаюсь с ним до сих пор, т.к. лень везде менять. Но в купикселях написано, что вызывать конкретный быстрее. Сканлайн я проверял, купиксели купикселят на 30% быстрее.
А что я не так делаю с купикселями?
← →
Вова (2013-06-29 11:30) [50]изменение формата я могу впринципе и убрать, оно там для "перестраховки". И даже могу передавать в процедуру уже не tbmp а сразу QP, только это врядли поможет, потому что аттач мне все равно нужно делать на новый кадр, и эта процедура вызывается раз на кадр.
← →
Anatoly Podgoretsky © (2013-06-29 11:49) [51]
> Я с самого начала выбрал 24 вот и мучаюсь с ним до сих пор,
> т.к. лень везде менять.
А что я не так делаю с купикселями?
А вот это.
← →
Inovet © (2013-06-29 11:52) [52]Помогите оптимизировать, но мне лень оптимизировать. Что-то напоминает.
← →
Вова (2013-06-29 12:29) [53]ох, вот самый конструктивный топик форума чуть не получился ) и началось )
← →
Вова (2013-06-29 12:37) [54]этот кусок это процентов 10 от всей программы, если вы таки считаете, что так легко все перелопатить. Тем более еще хз где мне это аукнется. Так что это пока не приоритет, когда буду точить напильником тогда. В принципе по данному куску, результат уже превзошел все мои ожидания )
← →
Вова (2013-06-29 12:38) [55]даж меньше 10
← →
Вова (2013-06-29 15:22) [56]
function ConvertBmpToRGBColorMapM(QP: TQuickPixels; var M: TMass;
Mass: TColorMapByte): Boolean;
var
Pixel1: Cardinal;
x: integer;
y: integer;
begin
for y := 0 to QP.Height - 1 do
begin
for x := 0 to QP.Width - 1 do
begin
Pixel1 := QP.GetPixels24(x, y);
// Pixel1 := ColorMap[numcol][Pixel1 shr 12 and $F0F or Pixel1 and $F0];
// FindConvertedColor(Pixel1, MainColor).color;
M.Mass[x + y * M.Xsize] := Mass[Pixel1 shr 12 and $F0F or Pixel1 and $F0];
end;
end;
Result := true;
end;
← →
Sha © (2013-06-29 16:27) [57]> Вова (29.06.13 11:22) [49]
> в купикселях есть общая процедура GetPixel, SetPixel и отдельная на каждый формат.
не нужны они тебе
> Но в купикселях написано, что вызывать конкретный быстрее.
на заборах тоже много чего понаписано, но тебе ж не приходить в голову проверять?
> Сканлайн я проверял, купиксели купикселят на 30% быстрее.
Бред. Ты опять что-то не то проверил. Зачем тебе надо кувыркаться с цветом?
А Прямое чтение из памяти всегда быстрее, чем любое действие, выполненное чужой процедурой.
> А что я не так делаю с купикселями?
вот это Pixel1 := QP.GetPixels24(x, y);
может, это поможет http://guildalfa.ru/alsha/node/14
> изменение формата я могу впринципе и убрать, оно там для "перестраховки".
все перестраховки делаются обычно в начале программы
Как я понимаю, тебе просто не хочется ускорить обработку кадра еще раз в 5-10.
Ну так посто скажи, и мы закончим лохматить бабушку.
← →
Вова (2013-06-29 21:21) [58]http://guildalfa.ru/alsha/node/16
← →
Вова (2013-06-30 14:21) [59]
function ConvertBmpToRGBColorMapM(tBmp: Tbitmap; var M: TMass;
Mass: TColorMapByte): Boolean;
var
Pixel1: Cardinal;
x: integer;
y: integer;
r,g,b:byte;
i, j: integer;
Row: ^byte;
Count:integer;
begin
IF tBmp.PixelFormat <> pf24bit then
exit;
Count := tbmp.Width * tbmp.Height;
Row := tbmp.ScanLine[tBmp.Height - 1];
repeat
r := row^;
inc(Row);
g := row^;
inc(Row);
b := row^;
Pixel1 := RGB(r,g,b);
M.Mass[Count-1] := Mass[Pixel1 shr 12 and $F0F or Pixel1 and $F0];
inc(Row);
dec(Count);
until Count=0;
получилось 10 миллисекунд, на купикселях 13. Но я чувствую что я написал тут какую то лажу
← →
Вова (2013-06-30 14:35) [60]на 8 битной 9 милисекунд
function ConvertBmpToRGBColorMapM(tBmp: Tbitmap; var M: TMass;
Mass: TColorMapByte): Boolean;
var
Pixel1: Cardinal;
i, j: integer;
Row: ^byte;
Count:integer;
begin
Count := tbmp.Width * tbmp.Height;
Row := tbmp.ScanLine[tBmp.Height - 1];
repeat
M.Mass[Count-1] := Mass[Pixel1 shr 12 and $F0F or Pixel1 and $F0];
inc(Row);
dec(Count);
until Count=0;
где 5-10 раз?
← →
Вова (2013-06-30 14:36) [61]ой, вместо Pixel1 там row^
← →
Sha © (2013-06-30 15:15) [62]0. Зачем опять проверять формат каждого кадра?
1. Адрес начала строки кратен 4. Поэтому если у тебя ширина картинки не кратна 4, то ScanLine надо вызывать для каждой строки.
2. Любой пиксел, кроме последнего, можно читать за одно обращение.
ppixel: pAnsiChar;
pixel: integer;
pixel:=pInteger(ppixel)^ and $FFFFFF; inc(ppixel,3);
Не надо никаких RGB, r, g, b - это лишнее.
← →
Sha © (2013-06-30 15:19) [63]> где 5-10 раз?
а где нормальная процедура?
← →
Вова (2013-06-30 16:01) [64]
> а где нормальная процедура?
да че то не получается пока )
← →
Sha © (2013-06-30 16:24) [65]1. Хинт: строки расположены в памяти с одинаковым смещением одна относительно другой. Подумай, как это можно использовать.
2. "Ничего кроме" означает "ничего кроме". Должно получиться нечто вроде Grayscale2 или Grayscale3, на которые я давал ссылку.
← →
Вова (2013-06-30 18:45) [66]
function ConvertBmpToRGBColorMapM(tBmp: Tbitmap; var M: TMass;
Mass: TColorMapByte): Boolean;
var
Count,h,w:integer;
ppixel: pAnsiChar;
pixel: integer;
begin
h := tbmp.Height-1;
repeat
ppixel:= tbmp.ScanLine[h];
w := 0;
repeat
pixel:=pInteger(ppixel)^ and $FFFFFF;
inc(ppixel,3);
M.Mass[(h)*tbmp.Width+w] := Mass[pixel shr 12 and $F0F or pixel and $F0];
inc(w);
until w = tbmp.Width-1;
dec(h);
until h=0;
Result := true;
end;
блин, боюсь что мне теперь не до скорости ) кое как перевернул картинку в нормальное состояние, но цвета вставляются все равно не те. И даже не то что красный вместо синего, а вообще хрен поймешь как...да и скорость 23мс. что с цветами? (
← →
Вова (2013-06-30 19:12) [67]попробовал менять в том же битмапе как в ссылке, но возник вопрос, а как в значение на которое указывает указатель AnsiChar записать Integer?
← →
Вова (2013-06-30 19:15) [68]Вообще я этот массив изобретал именно потому, что в нем быстрее все читается и пишется, поэтому я при первом же проходе битмапа (например при вычислении среднего перепада яркостей в том же цикле) выгружал в массив одновременно его переводя в градацию серого, а потом и в черно белый, получается что теперь обратно переделывать нужно? (
← →
Вова (2013-06-30 19:31) [69]
function ConvertBmpToRGBColorMapM(tBmp: Tbitmap; var M: TMass;
Mass: TColorMapByte): Boolean;
var
Count,h,w:integer;
ppixel: pAnsiChar;
pixel: integer;
pp : pInteger;
begin
h := tbmp.Height-1;
count := tbmp.Height * tbmp.Width;
repeat
ppixel:= tbmp.ScanLine[h];
pp := pInteger(ppixel);
pixel:=pInteger(ppixel)^ and $FFFFFF;
pp^ := ColorMap[Pixel shr 12 and $F0F or Pixel and $F0];
inc(ppixel,3);
dec(h);
dec(Count);
until h <0;
Result := true;
end;
че то ничего не происходит, картинка вообще не меняется.
← →
Вова (2013-06-30 20:04) [70]
function ConvertBmpToRGBColorMapM(var tBmp: Tbitmap; var M: TMass;
Mass: TColorMapByte): Boolean;
var
Count,h,w:integer;
ppixel: pAnsiChar;
pixel: integer;
pp : pInteger;
begin
h := tbmp.Height-1;
count := tbmp.Height * tbmp.Width;
ppixel:= tbmp.ScanLine[h];
repeat
pp := pInteger(ppixel);
pixel:=pInteger(ppixel)^ and $FFFFFF;
pp^ := ColorMap[Pixel shr 12 and $F0F or Pixel and $F0];
inc(ppixel,3);
dec(Count);
until Count <1;
Result := true;
end;
во нашел косяк....короче с цветами беда, не те он цвета показывает.
а до кучи даже в таком виде (без получение адреса каждой строке) 20 мс де то. Получается 10, это только в массив если фигачить причем в том же виде что и в памяти, т.е. вывернутом наизнанку.
← →
Вова (2013-06-30 20:08) [71]по моему купиксели выигрывают битву )) если конечно из за 3 миллисекунд не переделывать все на перевернутый массив )
← →
Вова (2013-06-30 20:46) [72]
function LockConvertBmpToRGBColorMapM(ppixel: pAnsiChar;Count:integer): Boolean;
var
//pixel: integer;
pp : pInteger;
begin
repeat
pp := pInteger(ppixel);
//pixel:=pInteger(ppixel)^ and $FFFFFF;
pp^ := ColorMap[pp^ shr 12 and $F0F or pp^ and $F0];
inc(ppixel,3);
dec(Count);
until Count <1;
Result := true;
end;
капитально ничего лишнего 16 миллисекунд. непонятные цвета. а на что влияет and $FFFFFF... я че то не понял вроде без него все также.
← →
Вова (2013-06-30 20:50) [73]да в массив наверное быстрее даж 10 будет, но в перевернутый (
← →
Sha © (2013-06-30 22:36) [74]> а на что влияет and $FFFFFF
Оно отрезает старший байт прочитанного из памяти целого i, т.к. нужный нам триплет лежит в младших байтах. Без него все также работает только потому, что при вычислении индекса в таблице старший байт не участвует: [i shr 12 and $F0F or i and $F0].//цикл по строке
repeat;
i:=pInteger(p)^;
pInteger(p)^:=ColorMap[i shr 12 and $F0F or i and $F0];
inc(p,3)
until p<last;
← →
Sha © (2013-06-30 22:40) [75]но в цикле [74] есть 2 ошибки
1. Затираем результатом то, что еще не обработали.
2. теоретически на последнем пикселе может быть AV из-за выхода за границу строки
Думай, как исправить
← →
Вова (2013-07-01 13:30) [76]
function LockConvertBmpToRGBColorMapM(ppixel: pAnsiChar;last:pAnsiChar): Boolean;
var
i : integer ;
begin
repeat;
i:=pInteger(ppixel)^;
pInteger(ppixel)^:=ColorMap[i shr 12 and $F0F or i and $F0];
inc(ppixel,4)
until ppixel=last;
Result := true;
end;
лол, а вот так 2 миллисекунды, ток все через черную полоску. и даж цвета похожи на те что я выводил
← →
Вова (2013-07-01 13:31) [77]последним пикселем можно пренебречь и не обрабатывать его вообще.
← →
Sapersky (2013-07-01 14:54) [78]Указатель увеличиваешь на 4, а цвет 24-битный, поэтому и полоска.
Скорость повышается из-за того, что доступ по выровненным на 4 адресам быстрее, чем невыровненный с шагом 3 (+ обращений на 25% меньше). Отсюда вывод - 32-битные битмапы должны быть быстрее, даже при большем размере данных.
Как вариант, результирующий битмап (или массив) можно сделать 8-битным, всё равно там цвета можно по пальцам пересчитать. Хотя не факт, что скорость при этом вырастет.
Проблемы с цветами видимо из-за того, что порядок цветовых компонент изменился, раньше было RGB, сейчас BGR. Нужно сдвиги и and"ы с масками поменять соот-но.
В целом, насчёт ускорения в 5-10 раз Sha всё-таки загнул. Не может такого быть за счёт отказа от вызова одной (несложной) функции и причёсывания всяких мелочей. Скорее уж проценты, а не разы.
При шаге 4 байта получились разы, но это другое.
← →
Sapersky (2013-07-01 15:17) [79]Или, если перейти на 32 бита сложно, ещё вариант - обрабатывать пачками по 4 пикселя (12 байт, 3 чтения по 4 байта). Опять же, развёртка цикла получается, тоже полезно.
Но для того чтобы выковырять эти 4 пикселя, понадобятся дополнительные сдвиги и and"ы. Функция станет совсем уж монструозной, через полгода сам без комментариев (и/или поллитры) не разберёшься.
← →
Вова (2013-07-01 16:36) [80]и в добавок эта битовая математика ад какой то, я ничего не могу в ней понять ) откуда все понимают какие маски накладывать и все такое..
← →
Sha © (2013-07-01 17:12) [81]> Sapersky
> В целом, насчёт ускорения в 5-10 раз Sha всё-таки загнул.
> ещё вариант - обрабатывать пачками по 4 пикселя
как бы нам это проверить... )
> Вова
> и в добавок эта битовая математика ад какой то
если скорость нужна, научишься и разберешься: )var
ColorMap: array[0..16*16*16-1] of integer;
procedure ShaConvert(p: pIntegerArray; rowcount, pixelcount: integer);
var
i, j, t, rest: integer;
begin;
pixelcount:=pixelcount*3;
while rowcount>0 do begin;
rest:=pixelcount;
while rest>=6 do begin;
i:=p[0];
j:=p[1];
t:=ColorMap[i shr 24 and $F0 or j shr 4 and $F0F];
i:=ColorMap[i and $F0 or i shr 12 and $F0F];
p[0]:=i or t shl 24;
if rest<12 then begin;
pWordArray(p)[2]:=t shr 8;
inc(pAnsiChar(p),6);
dec(rest,6);
break;
end;
i:=p[2];
j:=ColorMap[j shr 16 and $F0 or j shr 28 and $F or i shl 4 and $F00];
p[1]:=t shr 8 or j shl 16;
p[2]:=j shr 16 or ColorMap[i shr 8 and $F0 or i shr 20 and $F0F] shl 8;
inc(pAnsiChar(p),12);
dec(rest,12);
end;
if rest>0 then begin; //последний нечетный пиксел
i:=pWordArray(p)[0]+pByteArray(p)[2] shl 16;
i:=ColorMap[i and $F0 or i shr 12 and $F0F];
pWordArray(p)[0]:=i;
pByteArray(p)[2]:=i shr 16;
end;
dec(rowcount);
inc(pAnsiChar(p),(4-pixelcount) and 3);
end;
end;
← →
Вова (2013-07-01 17:22) [82]омг, ну ради такого профита можно перейти и на 32, но вот только все эти i and $F0 это писец ) статью выше я читал, понял не очень, но это по сравнению с той статьей вообще космос )
← →
Sha © (2013-07-01 17:24) [83]результат давай: проценты или разы?
← →
Вова (2013-07-01 17:24) [84]есть где нибудь описание "на пальцах" как вот это i shr 24 and $F0 or j shr 4 and $F0F понять? )
← →
Sha © (2013-07-01 17:38) [85]Там в коде [81] ошибочка вкралась, исправить надо:
if rest>0 then begin; //последний нечетный пиксел
i:=pWordArray(p)[0]+pByteArray(p)[2] shl 16;
i:=ColorMap[i and $F0 or i shr 12 and $F0F];
pWordArray(p)[0]:=i;
pByteArray(p)[2]:=i shr 16;
inc(pAnsiChar(p),3);
end;
← →
RWolf © (2013-07-01 17:41) [86]
> есть где нибудь описание "на пальцах"
учебник по информатике, 7-й класс.
← →
Вова (2013-07-01 17:42) [87]
> результат давай: проценты или разы?
пока только ошибка j:=p[1];
Если p := tbmp.Scanline(tbmp.Height-1)
← →
Sha © (2013-07-01 17:46) [88]У меня компилится без проблем. Ты мой код меняй.
Свой меняй. И свою секретную ошибку сюда давай.
← →
Sha © (2013-07-01 17:46) [89]* Ты мой код не меняй.
← →
Вова (2013-07-01 17:49) [90]я твой не менял, просто передал в функцию вот это...
← →
Вова (2013-07-01 17:50) [91]оно компилицо, оно при выполнении вылетает с access violation
← →
Sha © (2013-07-01 17:51) [92]Ошибка-то какая?
← →
Вова (2013-07-01 17:54) [93]First chance exception at $006389F5. Exception class $C0000005 with message "access violation at 0x006389f5: read of address 0x0444f000". Process SDIAPP.exe (66676)
← →
Sha © (2013-07-01 17:54) [94]а высоту в строках, ширину в точках передал?
← →
Вова (2013-07-01 17:59) [95]
T := GetTickCount;
p:= tbmp2.ScanLine[tbmp2.Height-1];
for I := 0 to 1000 do
ShaConvert(p, tbmp2.Height, tbmp2.Height*tbmp2.Width);
T := GetTickCount-T;
← →
Sha © (2013-07-01 18:00) [96]ShaConvert(p, tbmp2.Height, tbmp2.Width);
← →
Вова (2013-07-01 18:01) [97]хм.....да уж))
← →
Вова (2013-07-01 18:05) [98]3 миллисекунды, но меня смущает, что со второго раза в цикле, он начинает колбасить уже переколбашеный в первом цикле массив )
← →
Sha © (2013-07-01 18:07) [99]И че, ему все равно что колбасить, скорость процесса постоянна )
Ну, так все-таки разы? ))
← →
Вова (2013-07-01 18:08) [100]вместо желтого красный, появился голубой...
← →
Вова (2013-07-01 18:10) [101]ну по скорости да, но я как понял, 32 проще ) да и на 1 миллисекунду быстрее ))
← →
Sha © (2013-07-01 18:12) [102]1. правильные цвета будут только после однократного конвертирования,
конвертирование отконвертированного все ломает.
2. эта битовая математика - сущий ад, может что и не доглядел - найди и исправь )
← →
Вова (2013-07-01 18:13) [103]и потом это все же перевернутая картинка ) после переворачивания будет те же 10 мс ) т.е. чтобы извлечь профит надо с такой же как в памяти работать.
правда у купикселей, она встает по человечески по умолчанию, так что не проверить ( кроме того купиксели работают с одинаковой скоростью и с 24 битами и с 32 (
ну я отягощен мыслью что все нужно переделывать )))
← →
Sha © (2013-07-01 18:15) [104]> но я как понял, 32 проще ) да и на 1 миллисекунду быстрее ))
быстрее будет раза 2,
причем развернутый цикл легко переделать из моей процедуры
← →
Sha © (2013-07-01 18:17) [105]> и потом это все же перевернутая картинка )
> после переворачивания будет те же 10 мс
во-первых, нафига переворачивать?
во-вторых, ты вроде прогаммист, а программист может
перевернуть картинку в процессе обработки в том же цикле.
← →
Sha © (2013-07-01 18:18) [106]> купикселей, она встает по человечески по умолчанию
выпал в осадок
← →
Вова (2013-07-01 18:19) [107]ну когда я первый раз попробовал мне это дало лишних 10 миллисекунд, хотя там цикл был другой.
Переворачивать потому что у меня шаблоны то перевернутые, так что либо шаблоны переделывать, либо это переворачивать под шаблоны..
← →
Sha © (2013-07-01 18:21) [108]Шаблоы переворачивать один раз, картинку - постоянно.
Что выгоднее?
уууууу
← →
Вова (2013-07-01 18:24) [109]ну вот я и говорю, что нужно переделывать, чтоб шаблоны были перевернутые.
← →
Вова (2013-07-01 18:25) [110]вернее не перевернутые )
← →
Вова (2013-07-01 18:41) [111]интересно, а через SetDIBits будет еще быстрее чем через сканлайн? )
может уже чтобы 2 раза потом не переделывать разобраться)
← →
Sha © (2013-07-01 20:12) [112]> Вова (01.07.13 18:41) [111]
Если преобразовывать цвет в цвет, то быстрее [81,85] для 24-битного цвета не получится.
А если цвет в булеан, то можно отжать еще несколько процентов.
32-битный цвет, наверно, будет в 1.2-2.0 раза быстрее в зависимости от процессора.
← →
Sapersky (2013-07-02 07:19) [113]Ну, так все-таки разы? ))
Разы.
Мне показалось, что было утверждение вроде "выкинь купиксели и будет тебе 5-10 раз", только за счёт выкидывания. А оказывается в [57] уже была запланирована развёртка цикла с выравниванием доступа к памяти, кто бы мог подумать :)
← →
Sha © (2013-07-02 08:10) [114]кто ж всю лапшу сразу вываливает на клиента, так можно отпугнуть )
← →
Вова (2013-07-02 13:25) [115]блиииин! жил же спокойно (( раз рассказали все это теперь расскажите и что это значит
старший байт тот что в конце (слева направо)?
i := p[0]; //Берем первые 4 байта в строке (BGR + 1 байт канал B от следующего пикселя)
j := p[1]; //Берем вторые 4 байта в строке
Дальше ад:
T := ColorMap[i shr 24 and $F0 or j shr 4 and $F0F];
i shr 24 - смещение вправо 3 байт, т.е. остается канал B первого пикселя? правда он теперь на месте B второго пикселя. объединяется с `11110000` опять же не понятно как, i это же 4 байта, а не 1, или он только с последним самым правым байтом или со всеми по очереди? И главное - какой в этом смысл? Блин ну это ведь что то значит ) просто так наложили какую то лажу на канал цвета, что это с цветом то делает? ) т.е. 4 последних бита обнуляются, но нафига???
or j - первых 4 байта у которых значащими остались только первые 4 бита в последнем байте, накладываются на вторые 4 байта, получается вообще непонятно что )
j shr 4 - 4 правых бита от j удаляются. получается 4 байта с пустыми 4 битами в начале, и с какой то непонятной лажей (получившейся в результате or j) в самых правых 4 битах, а потом вообще ппц объединение с 111100001111, это ж полтора байта, как оно вообще накладывается (( на 4 байта! Обнуляются первые 4 бита правого байта? сдается мне что это не так, т.к почему тогда не 0F? ( но что за хрень это тогда?
В общем, к данному моменту кода у меня в голове полная каша не позволяющая идти дальше. Напоминает школу ) "В результате тривиальных вычислений получаем....." что получаем, откуда непонятно ( и как результат 10 впустую потраченных лет.
i := ColorMap[i and $F0 or i shr 12 and $F0F]; ну это понятно, см. выше ((
p[0] := i or T shl 24; - объединение 2х абракадабр, если у shl приоритет такой же как у or то вообще какая то херня, выкинули 3 байта остался 1 Оо
Все что я нашел об этом, это надписи о том, что в интернете куча статей об этом, видимо не такая уж и куча....Дайте ссылку хоть на одну! то что "1111000" or "00001111" = "11111111" это я вроде понял, только вот это никак не помогает понять, что в этом коде написано.
← →
Вова (2013-07-02 13:28) [116]блин (((
← →
Sha © (2013-07-02 13:51) [117]1. Байты в integer нумеруются с 0 до 3. Младший байт содержит содержит младшие 8 бит, т.е. остаток от деления на 256.
2. В теории, в голове и на бумаге младший байт обычно изображают слева, старший справа, (это похоже на десятичную систему, только здесь она 256-ричная).
3. В памяти машины с архитектурой IA-32 адрес integer совпадает с адресом его младшего байта, байт номер 1 хранится по адресу на 1 больше, старший байт - по адресу на 3 больше. Можно считать, что адреса растут справа налево.
4. Команды shr и shl имеют дело с представлением 2, причем сдвиг в действительности выполняется на указанное число бит, взятое по модулю размера операнда (т.е. 32 для integer).
5. Команды and и or с integer-операндами выполняются побитно, т.е. i and 1 вернет значение младшего бита младшего байта (1 для нечетного числа, 0 для четного), a i or 1 вернет первое нечетное после i для четного i или само i для нечетного i.
← →
Sha © (2013-07-02 13:54) [118]Зарапортовался, все с точностью до наоборот:
2. В теории, в голове и на бумаге младший байт обычно изображают справа, старший слева,
← →
Sha © (2013-07-02 14:10) [119]Допустим в переменной i лежит цвет,
интесивность каждой составляющей в своем байте (байты 0..2).
Пусть
i:=$00aabbcc;
Каждую из них усекаем до старших 4х битов:
i:=i and $F0F0F0;
Получаем
i:=$00a0b0c0;
Формируем число от 0 до 16*16*16-1 - будущий индекс цвета в таблице:
i:=(i shr 12 and $F) + (i and $F0) + (i shr 12 and $F00);
Получаем
i:=$00000acb;
Tот же самый результат дает
i:=i and $F0 or i shr 12 and $F0F;
← →
Sha © (2013-07-02 14:39) [120]Обрабатывать цвет по определению надо триплетами, читать-писать для скорости надо двойными словами.
Из-за этого небольшого противоречия возникают некоторые сложности с пониманием алгоритма )
Давай посмотрим это на простом примере. Пусть в памяти m последовательно лежат 4 байта. Надо первый из них увеличить на 1, второй умножить на 2, третий разделить на 3, четвертый оставить без изменений. Читать и писать переменную m разрешается только 1 раз.
Решение:i:=m;
m:=(i + 1) and $FF
or i and $7F00 shl 1
or i shr 16 and $FF div 3 shl 16
or i and $FF000000;
← →
Jeer © (2013-07-02 17:05) [121]Приятно, когда мастера общаются in self и это правильно:)
← →
Jeer © (2013-07-02 17:08) [122]P.S.
Что-то это мне напомнило "Радио? Это очень просто!" Айсберга.
Кстати, на самом деле, замечательный методический прием.
← →
Sha © (2013-07-02 17:41) [123]> Вова (02.07.13 13:25) [115]
че-то ты притих )
i shr 24 and $F0 - ставим нулевой байт второго триплета на нулевое место и оставляем в нем только 4 старших бита в старшем нибле,
j shr 4 and $F0F - ставим старший нибл первого байта второго триплета на место младшего нибла нулевого байта,
а старший нибл второго байта второго триплета на место младшего нибла первого байта,
or-им их между собой - получаем индекс для второго триплета в нашей таблице.
проще пареной репы )
> если у shl приоритет такой же как у or то вообще какая то херня
ну с приоритетами ты уж разберись, даже неудобно как-то, ты программист или где?
2+2*2=?
or j - первых 4 байта у которых значащими остались только первые 4 бита в последнем байте, накладываются на вторые 4 байта, получается вообще непонятно что )
j shr 4 - 4 правых бита от j удаляются. получается 4 байта с пустыми 4 битами в начале, и с какой то непонятной лажей (получившейся в результате or j) в самых правых 4 битах, а потом вообще ппц объединение с 111100001111, это ж полтора байта, как оно вообще накладывается (( на 4 байта! Обнуляются первые 4 бита правого байта? сдается мне что это не так, т.к почему тогда не 0F? ( но что за хрень это тогда?
В общем, к данному моменту кода у меня в голове полная каша не позволяющая идти дальше. Напоминает школу ) "В результате тривиальных вычислений получаем....." что получаем, откуда непонятно ( и как результат 10 впустую потраченных лет.
i := ColorMap[i and $F0 or i shr 12 and $F0F]; ну это понятно, см. выше ((
p[0] := i or T shl 24; - объединение 2х абракадабр, если у shl приоритет такой же как у or то вообще какая то херня, выкинули 3 байта остался 1 Оо
Все что я нашел об этом, это надписи о том, что в интернете куча статей об этом, видимо не такая уж и куча....Дайте ссылку хоть на одну! то что "1111000" or "00001111" = "11111111" это я вроде понял, только вот это никак не помогает понять, что в этом коде написано.
← →
Sha © (2013-07-02 17:43) [124]После 2+2*2=? не читай.
Это копипаста твоего поста
← →
Rouse_ © (2013-07-02 21:13) [125]Фига, Сань, у тебя конструкции:
or i shr 16 and $FF div 3 shl 16
Я понимаю, запятые там можно понапропускать, все равно читабельно будет - но зачем скобки то игнорировать на таких операциях? :)
Ни разу ж не читабельно :)
← →
Sha © (2013-07-02 21:17) [126]нормально читаю, с удовольствием:
or читается как +
and, shr, shl читаются как *
в чем проблема-то?
не понимаю )
← →
Rouse_ © (2013-07-02 21:22) [127]Ну я раза три перечитал сей код, дабы осмыслить :)
Оть так-же гораздо удобней:or (((i shr 16) and $FF) div 3) shl 16
← →
Sha © (2013-07-02 21:26) [128]Саш, ну ты мысленно сделай замену как в [126].
Стал бы ты тогда ставить скобки?
Согласись, они бы только мешали.
Ну вот и мне мешают. Потому и не ставлю )
← →
Rouse_ © (2013-07-02 21:28) [129]Да это-то понятно, просто мне в своем крипто приходится писать примерно такого-же плана конструкции (побольше, правда) и чтобы не запутаться кто от чего зависит я и привык все скобками обрамлять.
Ну а исходя из этого я на автомате за скобки глазом цепляюсь и влет разбиваю конструкцию на составляющие, а вот в твоем варианте пришлось подзадуматься (вчитаться тобишь...) :)
← →
Sha © (2013-07-02 21:31) [130]У меня другой прием:
куски, которые вычисляются по отдельности пишу каждый на своей строчке,
а внутри кусков операции выполняются последовательно.
В результате и ясно все, и скобки не нужны.
← →
Rouse_ © (2013-07-02 21:40) [131]Принцип понятен, но все равно не привычен (попробовал - ну не получается на автомате разбирать такие конструкции) :)
← →
Sha © (2013-07-02 21:46) [132]Я уже давно так пишу, привык.
Наоборот, скобки тормозят чтение кода.
А лишние скобки просто бесят. Потому, что пытаюсь понять, нафига их сюда впихнули, а вдруг это ошибка?
← →
Inovet © (2013-07-03 06:33) [133]> [127] Rouse_ © (02.07.13 21:22)
> Оть так-же гораздо удобней:
>
> or (((i shr 16) and $FF) div 3) shl 16
Ну, как бы наоборот - путают скобки.
← →
Inovet © (2013-07-03 06:34) [134]> [132] Sha © (02.07.13 21:46)
> понять, нафига их сюда впихнули
Вот.
← →
Вова (2013-07-03 18:38) [135]
> че-то ты притих )i shr 24 and $F0 - ставим нулевой байт
> второго триплета на нулевое место и оставляем в нем только
> 4 старших бита в старшем нибле,
я просто уже выпал в осадок. Я уже заметил что нет единого мнения где у чего начало и конец, натворили че попало, без картинок и ящика водки не разберешься.
11111111 11111111 11111111 11111111 shr 24 and $F0= 00000000 00000000 0000000 11110000
т.е. самый левый байт становится самым правым. это как я себе представлял, но и также я себе представлял, что именно самый правый был первым байтом второго триплета. Теперь я уже затрудняюсь себе что либо представлять (
или таки т.е. нулевой это самый правый, первый это второй справа и т.д. и т.е. самый левый на самом деле 3й )) ппц. Че за наркоман это придумывал.
← →
Sha © (2013-07-03 20:06) [136]Мы, пишушие слева направо, любим стрелки вдаль к бесконечности направлять направо,
а числа записывать так, чтобы разряды с бОльшим весом располагались слева.
И это создает проблему.
Когда мы мыслим число в вакууме, с заякоренным разрядом единиц,
то чем оно больше тем левее у него левый край.
Но то же, лежащее поразрядно в бесконечной памяти уходит далеко направо.
Так что лево/право весьма относительно.
Этой проблемы не было бы, если б мы считали, что адреса растут от нуля налево.
Но как только мы начнем так считать, то сразу же появится аналогичная проблема для строк.
Наверно, поэтому никто из пишущих направо так и не считает )
Резюмируя, можно сказать, что команды SHR и SHL относятся к числу в вакууме.
И если тебе так будет проще, можешь считать,
что в памяти число вывернуто наизнанку, и левый фланг у него справа )
← →
Вова (2013-07-03 20:38) [137]нет уш. Если у нас уже готовый битмап есть, то чтобы пройти от начала до конца строки, нужно идти справа на лево получается. так что это письмо справа налево. и т.е. получается что второй триплет левее первого... но сдвиг вправо я надеюсь правильно нарисовал?) а то может у них и сдвиг вправо на самом деле влево ))
← →
Sha © (2013-07-03 20:42) [138]Сдвиг у тебя правильный )
А второй триплет, тот который на экране правее первого,
расположен в памяти по адресу на 3 больше, чем адрес первого.
← →
Вова (2013-07-04 01:50) [139]12500670 =
10111110 10111110 10111110 shr 12 = 00000000 00001011 11101011 and $F0F =00000000 00001011 00001011
10111110 10111110 10111110 and $F0 = 10111110 10111110 10110000
00000000 00001011 00001011 or
10111110 10111110 10110000 =
10111110 10111111 10111011 = 12500923
и в чем тут смысл? да и по моему че то не так....
← →
Sha © (2013-07-04 10:18) [140]
$87654321 shr 12 = $00087654
$00087654 and $00000F0F = $00000604
$87654321 and $000000F0 = $00000020
$00000604 or $00000020 = $00000624
Мы сформировали число в интервале 0..4095 (индекс цвета в нашей таблице),
комбинируя старшие ниблы каждого из трех цветовых каналов.
Порядок следования исходных ниблов в полученном числе выбран таким,
чтобы обеспечить максимальную скорость преобразования цвета в индекс.
← →
DevilDevil © (2013-07-29 15:02) [141]> Вова (04.07.13 01:50)
подниму ка я ветку
пока работающий вариант с циклом for по X и по Y в 24 битах
оптимизирую
а то развели тут бардак ))
← →
DevilDevil © (2013-07-29 15:25) [142]*покажи
← →
Вова (2013-07-29 17:20) [143]
> *покажи
в 81м посте, но нафига, если 32 проще и быстрее работает.
← →
Sha © (2013-07-29 17:41) [144]> Вова (29.07.13 17:20) [143]
> если 32 проще и быстрее работает
хочешь поговорить об этом? )
← →
DevilDevil © (2013-07-29 17:44) [145]ok, покажи текущий код для 32 бита
← →
Вова (2013-07-29 18:06) [146]
> > Вова (29.07.13 17:20) [143]> если 32 проще и быстрее
> работаетхочешь поговорить об этом? )
ты же сам сказал, что по определению быстрее. Ну из того что я пробовал оно следует.
← →
Вова (2013-07-29 18:09) [147]
> ok, покажи текущий код для 32 бита
Там выше где то было, но вообще я еще не делал, мне под него программу нужно переделывать, время пока нет на это (
← →
DevilDevil © (2013-07-29 18:10) [148]> Вова (29.07.13 18:06) [146]
> ты же сам сказал, что по определению быстрее. Ну из того
> что я пробовал оно следует.
всё верно
в современном мире используют преимущественно 32 бита, даже если нет альфаканала
ибо проще и быстрее
"стильно модно молодёжно" хочется сказать :)
← →
DevilDevil © (2013-07-29 18:11) [149]> Вова (29.07.13 18:09) [147]
> Там выше где то было, но вообще я еще не делал, мне под
> него программу нужно переделывать, время пока нет на это (
ты меня прям обламал
хотел продемонстрировать высший пилотаж... а ты забросил
← →
Вова (2013-07-29 20:27) [150]
> ты меня прям обламал
> хотел продемонстрировать высший пилотаж... а ты забросил
не забросил, а отложил )
← →
Вова (2013-07-29 20:31) [151]как то так было:
function LockConvertBmpToRGBColorMapM(ppixel: pAnsiChar;last:pAnsiChar): Boolean;
var
i : integer ;
begin
repeat;
i:=pInteger(ppixel)^;
pInteger(ppixel)^:=ColorMap[i shr 12 and $F0F or i and $F0];
inc(ppixel,4)
until ppixel=last;
Result := true;
end;
> лол, а вот так 2 миллисекунды, ток все через черную полоску.
> и даж цвета похожи на те что я выводил
только я ему картинку неправильную давал
← →
DevilDevil © (2013-07-29 21:00) [152]> Вова (29.07.13 20:31) [151]
дак ты покажи рабочий вариант )
p.s.
и рассчёт индекса в табличке выглядит как-то странно
← →
Вова (2013-08-22 23:43) [153]итаг, я приступил к воплощению сего плана и начал переворачивать все шо не попадя. и вот ниже процедура, часть из которой закоментирована. И суть проблемы в том, что закоментированный и раскоментированный участки делают вроде бы одно и тоже. Но нижний участок при обратном преобразовании в битмап дает нормальные цвета. А вот тот что ща закоментирован, желтый делает голубым, голубой светлокоричневым и т.д. получается очень красиво, но нихрена не работает в результате. Почему так и как исправить верхний закоментированный кусок? )
function ConvertBmpToRGBColorMapM(tbmp:TBitmap; var M: TMass;
Mass: TColorMapByte): Boolean;
var
Pixel1,i,x,y:Integer;
Start,Stop:pInteger;
QP: TQuickPixels;
begin
// Start := tbmp.ScanLine[tbmp.Height - 1];
// Stop := tbmp.ScanLine[0];
// Pixel1:= 0;
// repeat
// i:= Start^;
// M.Mass[Pixel1] := i;
// //Mass[i shr 12 and $F0F or i and $F0];
// inc(Start);
// inc(Pixel1);
// until Start = Stop;
QP := TQuickPixels.Create;
QP.Attach(tbmp);
for y := 0 to QP.Height - 1 do
begin
for x := 0 to QP.Width - 1 do
begin
Pixel1 := QP.GetPixels32(x, y);
M.Mass[x + y * M.Xsize] := Pixel1;
//Mass[Pixel1 shr 12 and $F0F or Pixel1 and $F0];
end;
end;
Result := true;
QP.Free;
Result := true;
end;
← →
Sapersky (2013-08-23 00:10) [154][78]:
> Проблемы с цветами видимо из-за того, что порядок цветовых
> компонент изменился, раньше было RGB, сейчас BGR. Нужно
> сдвиги и and"ы с масками поменять соот-но.
Точнее BGRA, раз это 32 бита.
← →
Вова (2013-08-23 00:18) [155]
repeat
i:= Start^;
Start^ := ColorMap[i shr 12 and $F0F or i and $F0];
inc(Start);
inc(Pixel1);
until Start = Stop;
да (
проблемма в том, что я так и не понял что все это значит(i shr 12 and $F0F or i and $F0). Вообщем первую проблему то я решил.....но, при таком преобразовании, результат вовсе не такой как был раньше (
вместо желтого красный ну и т.д ( как поменять?
← →
Вова (2013-08-23 00:34) [156]
RGBV.red := color;
RGBV.green := color shr 8;
RGBV.blue := color shr 16;
блин, а это теперь тогда тоже не правильно? чот как не крутил все равно лажа (
← →
Sapersky (2013-08-23 00:50) [157]Проще всего как раз в этом месте поменять red и blue, чтобы не ковырять биты заново. И ещё i:= Start^ shr 8, чтобы привести BGRA к BGR.
← →
Вова (2013-08-23 00:57) [158]
> Проще всего как раз в этом месте поменять red и blue, чтобы
> не ковырять биты заново. И ещё i:= Start^ shr 8, чтобы
> привести BGRA к BGR.
не ( не помогает, еще больше цвета путаются.
ненавижу тех кто придумал вот эту хренотень с битмапами и всем вывернутым на изнанку ( и ниодной нормальной инструкции с картинками.
← →
Германн © (2013-08-23 01:13) [159]
> и ниодной нормальной инструкции с картинками
))))
← →
Вова (2013-08-23 01:21) [160]
TRGB = record
case integer of
1: (RGB: LongInt);
2: (B, G, R, O: BYTE);
var
rRGB:TRGB;
rrgb.RGB := ColorToRGB(color);
RGBV.red := rrgb.B;
RGBV.green := rrgb.G;
RGBV.blue := rrgb.R;
CODE</>
RGBV.red := color;
RGBV.green := color shr 8;
RGBV.blue := color shr 16;
оба варианта дают одинаковый результат. (второй старый на 24 бита был). то что было раньше желтым теперь красное, и появился голубой....откуда блин голубой, у меня в массиве его вообще нет.Function ConvertColorToRGBColorMap(color: LongInt; ColSel: string = "None")
: TColorWithName;
var
RGBV: trgbcolor;
bg: Boolean;
rb: Boolean;
rg: Boolean;
rRGB:TRGB;
begin
// rrgb.RGB := ColorToRGB(color);
// RGBV.red := rrgb.B;
// RGBV.green := rrgb.G;
// RGBV.blue := rrgb.R;
RGBV.red := color;
RGBV.green := color shr 8;
RGBV.blue := color shr 16;
rb := almostEqual(RGBV.red, RGBV.blue);
bg := almostEqual(RGBV.blue, RGBV.green);
rg := almostEqual(RGBV.red, RGBV.green);
with RGBV do
if rg and rb and bg then // тогда это серый или черный или белый
begin
if red > 230 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 bg 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 rb and (red > 130) then
begin
result.color := RGB(255, 0, 255);
result.Name := "Pink";
end // розовый
else if (blue < green) and (blue < red) and rg 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 (ColSel = result.Name) then
begin
result.color := 255; // картинка инвертирована для дальнейшей обработки
end
else
begin
result.color := 0;
end;
end;
Procedure InitColorMap();
var
i, j, k: byte;
begin
for i := 0 to 15 do
for j := 0 to 15 do
for k := 0 to 15 do
ColorMap[i * 256 + 16 * k + j] := ConvertColorToRGBColorMap
((i * 256 * 256 + j * 256 + k) * 16).color;
// for i:=0 to 15 do for j:=0 to 15 do for k:=0 to 15 do ColorMap[i*256+16*k+j]:=ConvertColorToRGBColorMap((i*16+15)*256*256+(j*16+15)*256+(k*16+15));
end;
Function ConvertBmpToRGBColorMap(var tBmp: Tbitmap;
ColSel: String = "None"): Boolean;
var
QP: TQuickPixels;
Pixel1: Cardinal;
x: integer;
y: integer;
i: integer;
numCol: byte;
Start,Stop:pInteger;
begin
if (tBmp.Height > 2) and (tBmp.Width >= 1) then
begin
numCol := TextColorToDigit(ColSel);
if numCol = 0 then
begin
Start := tBmp.ScanLine[tBmp.Height - 1];
Stop := tBmp.ScanLine[0];
repeat
i:= Start^;
Start^ := ColorMap[i shr 12 and $F0F or i and $F0];
inc(Start);
inc(Pixel1);
until Start = Stop;
end;
Result := true;
end
else
Result := false;
end;
← →
Вова (2013-08-23 01:47) [161]RGB(255, 255, 255);дело в этой функции...
← →
Sapersky (2013-08-23 01:49) [162]С битами всё объяснено в [119], только мне кажется лучше обозвать стандартными "цветными" буквами:
$00aabbcc -> $00000acb
$00RrGgBb -> $00000RBG
внезапно RBG, а не RGB. На этом можно сэкономить, B не двигать, R и G обрабатывать вместе.
Сейчас у нас (с учётом доп. сдвига i := Start^ shr 8):
$00BbGgRr -> $00000BRG
вроде ж всё очевидно: пара B_G двигается на 3 символа вправо (байт - два символа, сдвиг на полтора байта = shr 12), and $F0F отрезает всё лишнее. R никуда не двигается, просто отрезается лишнее маской $F0.
В результате имеем то самое шаманское заклинание.
А цвета в таблицу нужно подставлять в порядке BRG, получается.
Мог бы и сам понять, если бы внимательно читал, что тебе пишут...
← →
Вова (2013-08-23 02:02) [163]здорово что хоть кому то все очевидно...
т.к. мне и теперь стало еще непонятней чем было.
← →
Sapersky (2013-08-23 02:23) [164]Ну мне не сразу стало очевидно, пришлось вчитаться в [119].
Sha тоже хорош - изменил порядок цветов и упомянул об этом практически вскользь, я сначала подумал что acb это опечатка.
Делаем нормальный порядок цветов, хотя и менее оптимально:
$BbGgRr00 -> $00000RGB
R на 1 вправо, 4 бита.
G на 4 вправо, 16 бит.
B на 7 вправо, 28 бит.
i := Start^;
Start^ := ColorMap[(i shr 1 and $F) or (i shr 4 and $F) or (i shr 28)];
7 операций вместо 5.
← →
Sapersky (2013-08-23 02:25) [165]Всё-таки запутался в этих битах:
Start^ := ColorMap[(i shr 4 and $F) or (i shr 16 and $F) or (i shr 28)];
← →
Вова (2013-08-23 02:34) [166]ша тут нипричем, массив можно выкинуть вообще, и это ничего не изменит.
Start^ := ConvertColorToRGBColorMap(Start^).color;
т.е. вот такой код дает точно такой же результат. но... это значение вернула функция RGB(255,255,0); причем у меня там нет ниодной функции, которая генерит голубой цвет...а в итоговом бмп он есть...т.е. если даже допустить, что входной цвет у меня какой то неправильный, то выходной то как становится голубым? вот в чем вопрос )
← →
Вова (2013-08-23 02:41) [167]
function RGB(r, g, b: Byte): COLORREF;
begin
Result := (r or (g shl 8) or (b shl 16));
end;
во т.е. я так понимаю она как раз делает BGR? но в Start^ 4 байта, и куда прилепляется 4й?
← →
Sapersky (2013-08-23 02:41) [168]По поводу варианта с ColorToRGB - посмотрел бы, что она делает, Ctrl-клик и все дела.
В общем, не нужна она тут, rrgb.RGB := color должно работать.
Вариант со сдвигами - ещё в [21] писали, что нужно отрезать нужные байты масками.
← →
Вова (2013-08-23 02:48) [169]
function ColorToRGB(Color: TColor): Longint;
begin
if Color < 0 then
Result := GetSysColor(Color and $000000FF) else
Result := Color;
end;
← →
Вова (2013-08-23 02:58) [170]function RGB2(r, g, b: Byte): COLORREF;
begin
Result := (b or (g shl 8) or (r shl 16));
end;
методом научного тыка я выяснил, что теперь каналы как раз RGB и идут, а были BGR, а вот где альфа канал я так и не понял...
← →
Вова (2013-08-23 03:05) [171]твою машу, короче мозг сломаешь
RGBV.red := color shr 16;;
RGBV.green := color shr 8;
RGBV.blue := color;
входной так, выходной как в 170, вроде цвета на место встали и я запутался окончательно )
← →
Вова (2013-08-23 08:44) [172]мда уж, хоть с цветами все и решилось.
Но ночь плясок с бубном вокруг разворачивания изображения в разные стороны, отражения координат и т.д. и т.п. успехом не увенчались...
координата 0.0 картинки вовсе не тут Start := tBmp.ScanLine[tBmp.Height - 1];
и не тут!!! Stop := tBmp.ScanLine[0]; она вот тут: dec(Stop,tBmp.Width)
← →
Sha © (2013-08-23 10:21) [173]> Sha тоже хорош - изменил порядок цветов...
Так я вроде сказал, там выше, что это некий условный номер цвета )
Если особо не вдаваться в детали и не пытаться в этом номере
увидеть нечто большее, то все будет работать, как надо.
Ведь и при записи, и при чтении данных из таблицы мы
для одинаковых цветов будем вычислять одинаковый номер.
Поэтому абсолютно без разницы где там данные лежат в таблице
← →
Sha © (2013-08-23 10:40) [174]Таблица используется просто как кеш для запоминания результата функции.
Именно поэтому ей совершенно безразличен порядок цветов: RGB, BGR или
как еще. Альфа не кешируется.
← →
Sapersky (2013-08-23 16:12) [175]Поправки к [162] и [164]:
Я забыл, что при чтении как Integer порядок байт разворачивается, т.е. в памяти BGRA, в Integer ARGB.
Шаманское преобразование для 32-х бит будет $AaRrGgBb -> $RBG. И это таки влияет на порядок индексов при просчёте таблицы:
ColorMap[r * 256 + b * 16 + g] := ...
Для RGB:
ColorMap[r * 256 + g * 16 + b] := ...
Start^ := ColorMap[(i shr 12 and $F00) or (i shr 8 and $F0) or (i shr 4 and $F)];
← →
проф. Преображенский (2013-08-23 17:04) [176]Я "нет" говорю вместо "да",
Сажусь туда, где недавно был стул,
Я ложку несу мимо рта,
И просыпаюсь не там где уснул.
← →
проф. Преображенский (2013-08-23 18:37) [177]Я вижу суть вещей отныне,
Я слышу голос неземной,
А то, что сотворю в пустыне,
Узрят пришедшие за мной.
← →
Sha © (2013-08-24 08:52) [178]Предусмотреть все невозможно.
Успех меня опять не уберег.
Ну, нафига мне в руки вложен
Судьбой тот самый молоток?
← →
Вова (2013-08-24 11:37) [179]ощем, хз как разворачивать цикл. И акромя того, я таки стал разворачивать картинки в нормальное состояние (при переходе от бмп к массивам). Т.к. все расчитано на то, что картинка начинает обрабатывацо с левого верхнего угла, иначе если шаблон не на 100% накладываецо то всему писец. Да и полный размер программы в памяти ужо 100 мб, причем 2.8 экзешник и 97 база данных и картинки)) так что надо чо то с этим делать и битмапы нафиг слать.
← →
Вова (2013-08-24 11:56) [180]а вообще вопрос, целесообразно ли переходить от битмапа на одномерный массив. Особенно учитывая, что информация в битмапе явно избыточная, все что мне нужно помещается в 1 байте на пиксель, но очень важна скорость обработки. И еще есть ли смысл с обычным массивом работать через указатели( с точки зрения быстродействия)?
← →
Sha © (2013-08-24 12:25) [181]> все что мне нужно помещается в 1 байте на пиксель
и зачем тогда весь огород? столько времени строили...
> И еще есть ли смысл с обычным массивом работать через указатели
> ( с точки зрения быстродействия)?
небольшой дополнительный прирост можно получить,
но сначала алгоритм продумай и перейди на 1 байт, это даст гораздо больше
← →
Вова (2013-08-24 12:53) [182]как зачем, начинается то все со скриншота, но после обработки от него остается 1 байт на пиксель ) Хотя даже не байт, а бит ) т.е. после фильтрации все что мне нужно знать, есть в таком то месте пиксель или нет.
← →
Вова (2013-08-24 12:55) [183]а то что мы делали и была фильтрация и взятие скриншота, ну взятие скриншота потом переродилось в более редкое взятие скриншота в отдельном потоке и быстрое копирование его кусков в разные места )
← →
Вова (2013-08-24 13:06) [184]на байт я уже перешел давно, правда в процессе этого топика я усомнился, что так быстрее, наблюдая за тем как быстро обрабатывается битмап.
Т.е. базовый вариант, это берется кусок скрина и переводится в градацию серого в этот момент я переношу кусок битмапа в одномерный массив of Byte, после доп обработки, я переношу во второй массив точно такой же, но в нем у меня во всех точках либо 255 либо 0, т.е. по сути уже биты....
Вот кажется мне, что быстрее прям в битмапе переводить в серый, его обрабатывать и только потом переносить в массив с байтами....или с битами?
← →
Sapersky (2013-08-24 13:16) [185]Раз уж ты начинаешь задумываться об альтернативах TBitmap, предложу TFastDIB, там работа с 8-битными картинками достаточно удобна:
http://sourceforge.net/projects/tfastdib/files/Library/FastDIB%204.0/FastDIB%204.0.zip/download
Чтобы получить начало в левом верхнем углу, как я уже говорил, нужно задать отрицательную высоту.
1 бит на пиксель - не нужно, неудобно обрабатывать.
← →
Sha © (2013-08-24 13:52) [186]> Вова (24.08.13 13:06) [184]
Просто нет слов...
И что должно получиться в итоге?
← →
Вова (2013-08-24 16:00) [187]1) screenshot -> GrayScale -> Monochrome -> Search
2) screenshot -> Monochrome -> Search Это вариант который мы тут мучали, ничего не пропало зря. Просто мы преобразовывали битмап и в него же складывали результат, а на боевой результат копируется в массив байтов. хотя кажется мне что вот этим самым копированием замедляется работа (
← →
Вова (2013-08-24 16:05) [188]короче, просто взять битмап и отрезать от него нужный байт это не варинт ) так что не пойму, чего ты разволновался то )
← →
ProgRAMmer Dimonych © (2013-08-24 16:09) [189]> хотя кажется мне что вот этим самым копированием замедляется
> работа (
«Кажется» — это для астрологов и прочих экстрасенсов. У нас все копирования меряются и сравниваются с остальными операциями, выбирается самая медленная и оптимизируется. Процесс повторяется до получения приемлемого результата: при обработке больших массивов данных — до тех пор, пока не получится обрабатывать со скоростью, достаточной, чтобы данные не накапливались, при написании GUI-приложения — до тех пор, пока пользователь не перестанет замечать задержку во времени (кажется, около 100 мс — минимум, который можно ощутить).
← →
Вова (2013-08-24 16:38) [190]не ну я на самом деле проверял, если писать в тот же битмап из которого читаешь, то он быстрее работает, т.к. хотя бы потому, что операций меньше, не нужно в целевом массиве позиционироваться на нужную ячейку. А мне плюс к тому, еще приходится переворачивать изображение, т.к. Search для перевернутого изображения я сделать не смог, у меня критично чтобы поиск начинался с самой верхней точки объекта (и во вторую очередь с самой левой).
← →
Вова (2013-08-24 16:40) [191]*т.е. для неперевернутого....ну вообщем для такого как в битмапе ))
← →
Вова (2013-08-24 17:39) [192]ощема, вот так вот 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;
← →
Sha © (2013-08-24 17:41) [193]> Вова (24.08.13 16:00) [187], [188]
1. правильная работа массивом 1-байтных элементов будет заметно быстрее
2. все можно сделать за один проход
3. перевороты изображения - очевидный бред
4. рассуждения про скорость позиционирования - самоуспокаивающий бред
5. то, что ты не умеешь - не аргумент, учись
← →
Вова (2013-08-24 17:53) [194]1) однобайтный массив еще нужно получить в коде вверху я это и делаю.
2) несомневаюсь, но как перевернуть картинку в 1 проход я не знаю, и я не могу сделать то чего не знаю как сделать )
3) может и бред, но у меня не хватает воображения чтобы потом с отзеркаленым изображением работать (даже если его по вертикали развернуть легко, но еще нужно по x отразить). тем более что поиск должен идти сверху вниз и слева направо, т.е. если не перевернуть его тут, то потом при поиске все равно нужно извращаться. Что у меня и не получилось )
4) оке, за счет чего тогда в 2 раз медленней? без разворота будет 3-3.5 миллисекунды
5) все стоит времени и не всегда результат окупает затраты. Может и научусь, так ведь никто ж не ценит твоего времени и не показывает как. 20 минут гугла ничему мну не научили )
← →
Sha © (2013-08-24 18:49) [195]> оке, за счет чего тогда в 2 раз медленней?
за счет чего угодно, если интересно, приведи здесь оба кода, посмотрим
← →
Вова (2013-08-24 19:29) [196]
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.
← →
Вова (2013-08-24 19:36) [197]хе хе, попробовал второй массив через указатель, получилось на пол милисекунды медленней.
m^ := (Mass + (i shr 12 and $F0F or i and $F0))^;
← →
Вова (2013-08-24 19:39) [198]а нет....это не из за этого...
← →
Вова (2013-08-24 19:43) [199]ощем нет смысла бороться из за одной миллисекунды, т.к. тут еще и загруженность компа влияет и содержимое скриншота... так что это просто погрешность )
← →
Sha © (2013-08-24 19:51) [200]> ведь никто ж не ценит твоего времени и не показывает как
Пример чтения четырех пикселей за три операции в приведен [81].
Там же показано, как развернуть цикл и сэкономить на проверках.
В [12] и [119] разжевано кеширование результата функции.
По ходу обсуждения немного разобраны битовые операции.
В [193] в 100й раз повторено, что *ВСЯ* твоя задача решается
за один проход без предварительного копирования, переворотов и т.п.
Но это мало помогает, никто ж не ценит твоего времени, и не решает за тебя.
Имеет смысл учить только тех, кто хочет учиться.
← →
Вова (2013-08-24 21:07) [201]если цель программы научить кого то чему то, то там в изобилии должны быть комментарии объясняющие процесс. Ибо в 100 раз повторяю я не понимаю что происходит в [81]. Благодаря тем же причинам я не понимаю, что написано в твоем блоге, который я честно пытался читать, потому что там также стены кода в которых можно что либо понять, только если ты итак уже это знал.
имеет смысл учить на языке понятном обучаемому. Так что я выучил то что сумел понять.
← →
Sha © (2013-08-24 21:17) [202]значит, нам придется поработать над собой )
← →
Вова (2013-08-24 21:18) [203]равно как и в [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);
>
ну тут тоже все понятно ваще...и так далее )
← →
Плохиш © (2013-08-25 00:31) [204]Зачем оно тебе, это программирование? Тебе всë-равно не интересно.
PS. Вместо обид остановись, успокойся и подумай, что ты хочешь сделать.
← →
Sapersky (2013-08-25 03:26) [205]
> Вова (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 ещё чуть заковыристее, но принцип тот же.
Вот для этого последнего уровня оптимизации и нужно понимание битовых операций. А так, таблица она и есть таблица, с какими заклинаниями её ни вызывай.
← →
Sapersky (2013-08-25 03:39) [206]Строго говоря, таблица в первом и втором вариантах не of Integer, а of TRGB из [160], хотя я думаю и так можно сообразить, но кто ж Вову знает...
← →
Sha © (2013-08-25 12:30) [207]> Sapersky (25.08.13 03:26) [205]
вот, оказывается, где талант педагога скрывается )
← →
Вова (2013-09-02 01:58) [208]кстати хорошо или плохо если создать много потоков? ну там например 100? )) вообщем дело в том, что когда все делается в основном потоке, то делается это последовательно, и нельзя какое то звено тормознуть, т.к. этим ты тормознешь и тех кто идет следом. В то же время когда это делается в потоке, то процедура выполняется и ставится на паузу - т.е. во втором случае во первых никто не ждет пока процесс себя выполнит, т.к. он сам обновляет результат с необходимой переодичностью, во вторых процессор не шарашит как оголделый по 20 раз одно итоже и следовательно меньше нагружается. Я б даже сказал по опыту разница загрузки проца огромна. Хотя с другой стороны цикл основного процесса все равно будет носится и грузить проц. А во вторых в одно время выполняется только одна из веток программы, т.е. часть процедур может минут по 20 не использоваться, а если они в потоке будут крутиться, то постоянно, т.к. нужны они становятся по событию, а не по таймеру. вообщем сколько потоков юзать оптимально? особенно учитывая, что желательный режим работы на одном ядре (виртуальном) процессора?
на данный момент я как то забоялся делать много потоков (таки может и зря?) и только несколько процессов туда поместил, а остальное в основном кручу. Т.е. класс создается, но не запускается и процедуры выполняются в основном потоке его )
← →
Sha © (2013-09-02 09:41) [209]1. А что в книжках про это пишут?
2. Новые обсуждения лучше затевать в новых ветках.
3. А про коней в вакууме лучше в разделе "Прочее"
← →
ProgRAMmer Dimonych © (2013-09-02 21:22) [210]> забоялся делать много потоков (таки может и зря?) и только
> несколько процессов туда поместил
Осторожнее с понятиями: таки слово процесс уже зарезервировано для обозначения кой-чего другого, чем кусок кода, и в том значении как раз несколько потоков в процессе, а не наоборот :)
Страницы: 1 2 3 4 5 6 вся ветка
Текущий архив: 2014.07.06;
Скачать: CL | DM;
Память: 1.1 MB
Время: 0.013 c