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

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

ScanLine?


Страницы:   1 2

{RASkov} ©   (2007-06-02 15:31:00) 

Как можно быстрым способом получить средний цвет битмапа размером 100х100 пикселей
Нужена помощь с самим алгоритмом определения, со СканЛайн раньше никогда не работал, но думаю, что как раз с ним и нужно здесь...
Пояснение: Битмап имеет оттенки серого - нужно как бы сложить все цвета пикселей и разделить на их(пикселей) кол-во.. или как по другому?
Размер Битмапа тоже может меняться, указал средний...
Математика - это не мое, поэтому прошу помощи )


{RASkov}   (2007-06-04 15:09:00) [1]

> [31] DVM ©   (04.06.07 14:41)

Да собственно это не совсем мне нужно, да и рассказать в двух словах фик знаю как.
Нужно массив заполнить значениями = среднему цвету каждого пикселя данной картинки.
Двумерный Массив Byte Т.е. нужна одна состовляющая RGB - они же в оттенках серого все одинаковые
R=G=B, после нужно строить другой массив с использование данных из данного массива, но с учетом
некоторой переменной, и массив, грубо говоря, булевый.....массимы меньше размерностями, чем исходная картинка.
грубо говоря, тот битмап, что в сабже это часть общей картинки в оттенках серого..... в общем думаю понятно?


Sapersky   (2007-06-04 14:42:00) [2]

Лучше — всегда работать только с 32-х битным цветом.

Я бы не рискнул так категорично.
В некоторых случаях - да:
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1180439487&n=9[12]
Но для попиксельной обработки, ИМХО, особого преимущества 32bpp не даёт (за исключением MMX, и то не всегда), а места занимает больше.

Посмотрите в отладчике такой код, все врзу на места встанет.

Ну, 2 mov вместо 1. Но меньший объём перемещаемых данных это часто компенсирует. А уж тупой Move (BitBlt) 24->24 точно быстрее, хотя вообще, конечно, лишних "тупых Move" следует избегать.
При покомпонентной обработке (r, g, b отдельно) вообще должно быть без разницы, а если она и есть, то из-за интенсивного использования массивов-указателей вроде PRGBArray (для 24 бит Дельфи расписывает умножение x * 3 как x * 2 + x, из-за чего добавляется лишнее действие). Через обычные указатели разницы почти нет, где-то 3-5% (проверено на FastLIB'овских FastResize/Bilinear).

Кстати, в [2] код "более правильный", так как там параметр pf24Bit точно соответствует размеру записи (3 байта)

Размер записи и там, и там 3 байта.


DVM   (2007-06-04 14:41:00) [3]


> {RASkov} ©

А зачем тебе вообще понадобился этот средний цвет, если не секрет?


{RASkov}   (2007-06-04 14:27:00) [4]

После знака равно время показанное модулем PerfTimer.

GetBitmapColor 70 = 67828
GetAverageBitmapColor 70 = 66896
Sredniy 111 = 115364
GetAverageColor 100 = 94116
GetAverageBitmapColorGray 40 = 45899
QPixSredniy 380 = 371410
__________________
96 - $00000060
5066061 - $004D4D4D
13355979 - $00CBCBCB
13290186 - $00CACACA
5066061 - $004D4D4D
0 - clBlack
В Image1 загружена небольшая(350х135) картинка в оттенках серого..


{RASkov}   (2007-06-04 14:09:00) [5]

> [28] DVM ©   (04.06.07 14:02)

Спасибо, но я думаю, в общем-то картина не измениться...
Т.е. однозначно твой вариант (и его модификации) самый быстрый в этой ветке :)


DVM   (2007-06-04 14:02:00) [6]

Используй так:

TimeReset;
// делаем что-то;
TimeShowMks;


DVM   (2007-06-04 14:01:00) [7]


> {RASkov} ©   (04.06.07 13:54) [26]

Используй лучше счетчики производительности:


unit PerfTimer;

interface

procedure TimeReset;
function TimeMs: Integer;
function TimeMks: Integer;
function TimeRealMks: Double;
function TimeStrMs: String;
function TimeStrMks: String;
procedure TimeShowMks;

implementation

uses Windows;

var
 PCTime1, PCTime2, PCFreq: Int64;
 PCEnabled: boolean = False;

//------------------------------------------------------------------------------

procedure QueryPerformanceCounter(var Cnt : Int64);
var
 Thread, OldMask : DWord;
begin
 Thread := GetCurrentThread;
 OldMask := SetThreadAffinityMask(Thread, 1);
 QueryPerformanceFrequency(PCFreq);
 PCEnabled := (PCFreq <> 0);
 Windows.QueryPerformanceCounter(Cnt);
 SetThreadAffinityMask(Thread, OldMask)
end;

//------------------------------------------------------------------------------

procedure TimeReset;
begin
 QueryPerformanceCounter(PCTime1);
end;

//------------------------------------------------------------------------------

function TimeMs: Integer;
begin
 if PCEnabled then
   begin
     QueryPerformanceCounter(PCTime2);
     Result := ((PCTime2 - PCTime1) * 1000 ) div PCFreq;
     PCTime1 := PCTime2;
   end
 else
   Result := 0;
end;

//------------------------------------------------------------------------------

function TimeMks: Integer;
begin
 if PCEnabled then
   begin
     QueryPerformanceCounter(PCTime2);
     Result := ((PCTime2 - PCTime1) * 1000000 ) div PCFreq;
     PCTime1 := PCTime2;
   end
 else
   Result:=0;
end;

//------------------------------------------------------------------------------

function TimeRealMks: Double;
begin
 if PCEnabled then
   begin
     QueryPerformanceCounter(PCTime2);
     Result := ((PCTime2 - PCTime1) * 1000000 ) / PCFreq;
     PCTime1 := PCTime2;
   end
 else
   Result := 0;
end;

//------------------------------------------------------------------------------

function TimeStrMs: String;
var
 i: Integer;
begin
 i := TimeMs;
 Str(i, Result);
end;

//------------------------------------------------------------------------------

function TimeStrMks: String;
var
 i: Integer;
begin
 i := TimeMks;
 Str(i, Result);
end;

//------------------------------------------------------------------------------

procedure TimeShowMks;
var
 i: Integer;
 s: String;
begin
 i := TimeMks; Str(i, s);
 MessageBox(0, PChar(s), 'Time elapsed, mks ', MB_OK or MB_ICONWARNING);
end;

//------------------------------------------------------------------------------

initialization
 QueryPerformanceFrequency(PCFreq);
 PCEnabled := (PCFreq <> 0);

finalization

end.


{RASkov}   (2007-06-04 13:54:00) [8]

GetAverageBitmapColor     - 80 - 5066061 - $004D4D4D
GetAverageBitmapColorGray - 50 - 5066061 - $004D4D4D
И даже переделанная только под оттенки серого она возвратила одинаковый результат... по скорости чуть стала быстрее...


{RASkov}   (2007-06-04 13:46:00) [9]

> [24] homm ©   (04.06.07 04:20)

60 и 50 - я не беру во внимание разницу (10) , а вот 381 и 50 - здесь разница ощутимая...

> А вообще не понятно, как так от выбора алгоритма (а точнее
> реализации, алгоритм один и тот-же) может зависить результат.

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


homm   (2007-06-04 04:20:00) [10]

GetBitmapColor 60
GetAverageBitmapColorGray 50

Учитывая разрешение выбраной функции для подсчета производительности, результат РАВНЫЙ. Тестируй тчательнее. А вообще не понятно, как так от выбора алгоритма (а точнее реализации, алгоритм один и тот-же) может зависить результат.


{RASkov}   (2007-06-04 02:42:00) [11]

> [22] Andy BitOff ©   (03.06.07 03:35)
> И подивись скорости.


Самый медленный вариант(

---------------------------------
GetBitmapColor 60
GetAverageBitmapColor 80
Sredniy 120
GetAverageColor 100
GetAverageBitmapColorGray 50
QPixSredniy 381
__________________
96 - $00000060
5066061 - $004D4D4D
13355979 - $00CBCBCB
13290186 - $00CACACA
5066061 - $004D4D4D
0 - clBlack
И результат не понятный...

Это с учетом того, что создание и убиение я вынес за приделы функции... хотя скорости это нисколько не добавило к исходному варианту в [22]

Вот код теста:
 Memo1.Lines.Add('---------------------------------');
 T:=GetTickCount;
 for N := 0 to 255 do Cl:=GetBitmapColor(Image1.Picture.Bitmap);
 T1:=GetTickCount-T;
 Memo1.Lines.Add('GetBitmapColor '+IntToStr(T1));
 T:=GetTickCount;
 for N := 0 to 255 do Cl2:=GetAverageBitmapColor(Image1.Picture.Bitmap);
 T1:=GetTickCount-T;
 Memo1.Lines.Add('GetAverageBitmapColor '+IntToStr(T1));
 T:=GetTickCount;
 for N := 0 to 255 do SrCl:=Sredniy(Image1.Picture.Bitmap);
 T1:=GetTickCount-T;
 Memo1.Lines.Add('Sredniy '+IntToStr(T1));
 T:=GetTickCount;
 for N := 0 to 255 do ClAv:=GetAverageColor(Image1.Picture.Bitmap);
 T1:=GetTickCount-T;
 Memo1.Lines.Add('GetAverageColor '+IntToStr(T1));
 T:=GetTickCount;
 for N := 0 to 255 do ClG:=GetAverageBitmapColorGray(Image1.Picture.Bitmap);
 T1:=GetTickCount-T;
 Memo1.Lines.Add('GetAverageBitmapColorGray '+IntToStr(T1));

 qSource := TQuickPixels.Create;
 Image1.Picture.Bitmap.PixelFormat := pf24Bit;
 qSource.Attach(Image1.Picture.Bitmap);
 T:=GetTickCount;
 for N := 0 to 255 do QClG:=QPixSredniy(Image1.Picture.Bitmap);
 T1:=GetTickCount-T;
 qSource.Free;
 Memo1.Lines.Add('QPixSredniy '+IntToStr(T1));

Собственно все на равных условиях... Да... это до ужаса криво все, но мне нужно было только узнать скорость работы данных функций...
Еще пять это все модификации [2] и [3]....

GetBitmapColor 60
GetAverageBitmapColor 80
GetAverageBitmapColorGray 50
это [2]
остальные это - два(Sredniy и GetAverageColor) варианта[3] и функция с классом TQuickPixels из [22]
Вот так вот...


Andy BitOff   (2007-06-03 03:35:00) [12]

Попробуй еще вот это:
function Sredniy(Source: TBitMap): TColor;
var
 i, j: integer;
 r: byte;
 qSource: TQuickPixels;
begin
 qSource := TQuickPixels.Create;
 Source.PixelFormat := pf24Bit;
 try
   qSource.Attach(Source);
   r := 0;
   for i := 0 to qSource.Height - 1 do begin
     for j := 0 to qSource.Width - 1 do begin
       r := r + GetRValue(qSource.GetPixel(j, i));
     end;
   end;
   r := r div (qSource.height * qSource.Width);
   Result := RGB(r, r, r);
 finally
   qSource.Free;
 end;
end;

И подивись скорости.

TQuickPixels = http://www.delphimaster.ru/articles/pixels/index.html


{RASkov}   (2007-06-03 00:40:00) [13]

> [14] DVM ©   (02.06.07 18:16)

Работает отлично... и с моими поправками(См в [12]) применеными к [2,14]) даже еще чуть-чуть быстрее, и на порядок выше по скорости чем [3,12].
>
Всем спасибо.


homm   (2007-06-02 19:05:00) [14]

> С чего бы это?

Выравнивание памяти по 4 байта думаете с потолка во всех языках? 1 пиксель - одно машинное двойное слово, величина разрдности процессора. Напрямую читаем, напряму работаем, складываем, вычитаем, делим, и кладем обратно. Все это без лишнего очищения старшегго байта. Посмотрите в отладчике такой код, все врзу на места встанет.
var
 a, b: TRGBTriple;
 c, d: TRGBQuad;
 i: DWORD;
begin
 b := TRGBTriple((@i)^);
 a := b;

 d := TRGBQuad(i);
 c := d;

 form1.tag := a.rgbtBlue;
 form1.tag := c.rgbBlue;


DVM   (2007-06-02 18:34:00) [15]


> Лучше — всегда работать только с 32-х битным цветом.

С чего бы это?


antonn   (2007-06-02 18:34:00) [16]


> Лучше — всегда работать только с 32-х битным цветом.

сказал - как отрезал:)


homm   (2007-06-02 18:30:00) [17]

> Кстати, в [2] код "более правильный", так как там параметр
> pf24Bit точно соответствует размеру записи (3 байта). Видимо,
> способ хранения пикселей в твоем Битмапе использует 4 байта
> на пиксель, поэтому TRGB из [2] работает. Но лучше явно
> сделать структуру такой:

Лучше — всегда работать только с 32-х битным цветом.


DVM   (2007-06-02 18:18:00) [18]

небольшоая поправка

Count := Bmp.height * Bmp.Width;


Loginov Dmitry   (2007-06-02 18:18:00) [19]

Кстати, в [2] код "более правильный", так как там параметр pf24Bit точно соответствует размеру записи (3 байта). Видимо, способ хранения пикселей в твоем Битмапе использует 4 байта на пиксель, поэтому TRGB из [2] работает. Но лучше явно сделать структуру такой:

TRGB = record
 B, G, R, Alpha: Byte;
end;


DVM   (2007-06-02 18:16:00) [20]


> {RASkov} ©   (02.06.07 18:02) [12]

В моем варианте все работает как надо, надо просто поправить его как сказано выше было:


function GetBitmapColor(Bmp: TBitmap): TColor;
const
Pixels = MaxInt div SizeOf(TRGBTriple);
type
PRGBArray = ^TRGBArray;
TRGBArray = array[0..Pixels-1] of TRGBTriple;
var
x, y: Integer;
Row: PRGBArray;
SumR: integer;
SumG: integer;
SumB: integer;
Count: integer;
begin
SumR := 0;
SumG := 0;
SumB := 0;
Count := Bmp.Width * Bmp.Width;
Bmp.PixelFormat := pf24bit;
for y := 0 to Bmp.Height - 1 do
  begin
    Row := Bmp.ScanLine[y];
    for x := 0 to Bmp.Width - 1 do
      begin
        inc(SumR, Row[x].rgbtRed);
        inc(SumG, Row[x].rgbtGreen);
        inc(SumB, Row[x].rgbtBlue);
      end;
  end;
result := RGB(SumR div Count, SumG div Count, SumB div Count);
end;


Страницы:   1 2

Наверх

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