26. oktober 2000 - 10:53Der er
10 kommentarer og 1 løsning
Masser af pixels....
I forbindelse med realtime behandling af data fra et videokamera, skal jeg ha\' sat en værdi afhængigt lystyrken (Y) i en pixel værdi. Det ligger lige som i luften, at behandlingen skal gå hurtigt, idet der i sagens natur kommer mange data hvert sekund fra et 640*480 pixels kamera.
Det jeg ønsker er at få en outputværdi på enten $00 eller $FF anhængigt af om input værdien er over eller under en værdi på $80.
I alm. Object Pascal kan det udtrykkes som:
If Y>127 Then X := 255 else X := 0;
Laves denne forespørgelses/assignment kombination for hver indkommen pixel, går CPU belastningen på min 650 MHz Pc fra 20 til ~55% - det er ikke rigtigt holdbart. Jeg har en ide om, at jeg kan droppe forspørgelsen, dvs. If-delen, og istedet lave det om til en gang logisk algebra evt i kombination med noget bit shifteri/rotation, i et assignment, som jeg så formoder er hurtigere. Noget i retning af
X := (Y And $80) ... ... ..
Men hvorledes... Parantesen (Y And $80) vil altid resultere i en værdi på enten $00 eller $80 - det skal altså bare laves om til 0 og $FF. (Jeg kan godt acceptere en værdi på $01 istedet for $00 - hvis det gør sagerne nemmere fx i fbm. en rotation).
Jeg tror at jeg har løst problemet selv (så\'en går det når man skal forklare det til andre....).
Nedenstående bør gøre tricket:
X := ($FF00 SHR ((X AND $80) SHR 4) AND $FF;
Det indgår nu 4 logiske operationer + noget der ligner 4 load accumulator opeartioner.... gad vide om det er hurtigere end en IF sætning, men det skal en test vise. 1 cpu cycle/pixel kan ses når der behandles ca. 9 mill pixels pr. sekund.
Delphi
PS: Pointsne er stadig ude, hvis der er en anden der kommer med et lignende svar inden for ~5 min eller evt et bedre svar på et senere tidspunkt.
Hvordan kigger du på dine pixels?. Hvis du kigger på dem en pixel af gangen så tager det en evighed (og lidt til). I stedet skal du bruge ScanLine <SNIP> procedure TForm1.Button1Click(Sender: TObject);
// This example shows drawing directly to the BitMap var x,y : Integer; BitMap : TBitMap; P : PByteArray; begin BitMap := TBitMap.create; try BitMap.LoadFromFile(\'..\\Images\\Splash\\256color\\factory.bmp\'); for y := 0 to BitMap.height -1 do begin P := BitMap.ScanLine[y]; for x := 0 to BitMap.width -1 do P[x] := y; end; Canvas.draw(0,0,BitMap);
Der er ikke tale om pixels på en skærm. som jeg skrev kommer de fra et kamera. Rent faktisk fra et Sony DFW-V500 kamera forbundet til en Fire wire. Dataene leveres i en buffer (stort array) fra driverene.
Som regl kan det ikke svare sig .... nej. Det var nu også mere for at anskugeligøre mit argument om at det første kode var hurtigere end den andet .... Dog lod det ikke til at mine argumenter vandt megen indpas hos hin spørger.
bare fordi man koder assembler kan man vel godt have en hest eller to gående/travende rundt i koden ..... eller hvad ?
Ja nogle gange når man kigger på andres kode så kan det da godt se ud som om en HEST eller to har travet rundt i det :-)
Desværre var jeg ikke selv i besidelse af en PC da jeg i sin tid blev undervist i Assembler så det hang ikke så godt fast. Jeg havde i de gode gamle TP7 dage en del strengroutiner i assembler, men i forbindelse med Delphi valgte jeg at omskrive den til Delphi kode.
Nu er antallet af assembler instruktionen ikke nødvendigvis det samme som tid - ihvertfald skal man tage hensyn til typen af instruktioner. Her underneden kigger jeg på borris\'s kode. Jeg vælger at se bort fra alle RET\'s idet jeg jo liggger og drøner rundt i en løkke, hvor der ikke er tid til at involvere procedure kald. Jeg tager mig lidt friheder, idet jeg anvender lidt andre modes end i borris\'s kode, bl.a. er jeg inde i et array for at hente mine data (Based Indexed)
Tallet foran kommandoerne er det antal cycles der skal benyttes i de aktuelle addreserings modes:
17 mov eax, (BP)+(SI) 2 mov ecx,eax 4 and ecx,$80 2 shr ecx,$04 4 mov eax,$ff00 12 shr eax,cl // Jeg er lidt usikker på tallet her - det kan være 4. 4 and eax,$ff 17 mov (BP)+(SI), ax --- 62 cycles (måske 54)
eler hvis man flytter de fælles MOV instruktioner væk:
28 (evt 20) imod 23/27 cycles. - Det er her helt klart jump instruktionerne der tager tiden.
Det er første gang i mere end 10 år hvor jeg har haft brug for at tune et program på den måde. Men der sker altså noget når der ryger 9.000.000 pixels (af 16 bit) ind pr sekund - så hver cpu cycle tæller.
Placer 2 knapper og 2 labels på en form og prøv det her :
Function GetTimeStamp : Int64; var TimeStamp : Record case byte of 1 : (Whole: Int64); 2 : (LO, HI : longint); end; begin asm db $0F; db $31; mov [TimeStamp.LO], eax mov [TimeStamp.HI], edx end; Result:=TimeStamp.Whole; end;
procedure TForm1.Button1Click(Sender: TObject); var Start, Stop : Int64; i : integer; y : integer; begin Start := GetTimeStamp;
Nå men der hvor jeg etenlig ville hen var at jeg med mit lille korte eksempel ikke kan får tingende til at passe ... Og anyway nu er du udstyret med en nem måde til at tællt clock cycels med ....
Jens B
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.