SRL Archive - SRL Snippets

new PixelShift function


m34tcode

2012-03-20 20:51:34

I've been working on a new PixelShift function that, while similar to the SRL PixelShift, should be much more accurate.

The basic procedure is this:
  • Capture all the pixel colors within a specified bow
  • Capture all the pixels in the specified box again, and any pixels that have changed, are removed from the array
  • Repeat until we have run out of time(specified in paramaters) or have looped x number of times
  • This resulting array will contain all pixels whose colors changed beyond a specified tolerance

After a few repetitions inside of the PixelShift loop, You should be left with all the pixels in the box that your character animated over.

The tolerance is used to make sure that a small color in your surroundings does not throw the entire function off, and return a very low pixelshift.

I have not tested and fully worked the bugs out of this yet, and any help with that would be appreciated ;)

Here is the code so far:
{$DEFINE SMART}
{$i srl/srl.simba}
{$i srl/srl/misc/paintsmart.simba}

function GetColArr (Box : TBox) : T2DIntegerArray;
var
x,y : Integer;
begin
SetArrayLength(Result,box.X2-box.X1);
for x := 0 to box.X2-box.X1-1 do
begin
SetArrayLength(Result[x],box.Y2-box.Y1);
for y := 0 to box.Y2-box.Y1-1 do
begin
Result[x][y] := GetColor(x+box.X1,y+box.Y1);
end;
end;
end;

procedure ValidatePixels(Box : TBox; OrigCols : T2DIntegerArray; BoolArr : array of TBoolArray; Tolerance : Integer);
var
X,Y : Integer;
NewCols : T2DIntegerArray;
begin
NewCols := GetColArr(Box);
for X := 0 to Box.X2 - Box.X1-1 do
for Y := 0 to Box.Y2 - Box.Y1-1 do
begin
if not BoolArr[x][y] then
continue;
boolArr[x][y] := SimilarColors(origCols[x][y],NewCols[x][y],Tolerance);
end;
end;

function InitBoolArr(Width,Height : Integer) : array of TBoolArray;
var x,y : Integer;
begin
SetArrayLength(Result,Width);
for x := 0 to Width-1 do
begin
SetArrayLength(Result[x],Height);
for Y := 0 to Height-1 do
begin
Result[x][y] := True;
end;
end;
end;

function countBools(BoolArr : Array of TBoolArray; CountTrues : Boolean) : Integer;
var
X,Y,W,H,C : Integer;
begin
W := GetArrayLength(BoolArr);
H := GetArrayLength(BoolArr[0]);
For X := 0 to W-1 do
for Y := 0 to H-2 do
if BoolArr[X][Y] = CountTrues then
Inc(C);
Result := C;
end;

function CalculateNewPixelShift(Box : TBox; ShiftInterval, Repetitions, Tolerance : Integer) : Integer;
var
I,X,Y : Integer;
T,TT : LongInt;
OrigColArr : T2DIntegerArray;
BoolArr : array of TBoolArray;
begin
OrigColArr := GetColArr(Box);
BoolArr := initBoolArr(Box.X2-Box.X1,Box.Y2-Box.Y1);
MarkTime(T);
MarkTime(TT);
for I := 0 to Repetitions-1 do
begin
if (TimeFromMark(T) > (Repetitions*ShiftInterval)) then
begin
writeln('Completed only ' + IntToStr(I) + ' of '
+ IntToStr(Repetitions) + '. Try increasing the interval');
break;
end;
wait(Max(0,ShiftInterval-TimeFromMark(TT)));
MarkTime(TT);
validatePixels(Box,OrigColArr,BoolArr,Tolerance);
end;
for x := 0 to box.x2-box.x1-1 do
for y := 0 to box.y2-box.y1-1 do
if boolArr[x][y] then
SMART_DrawDot(false,Point(x+box.x1,box.y1+y),clRed);
Result := countBools(BoolArr,False);
end;

var
T : Longint;
Box : TBox;
begin
{$ifdef SMART}
Smart_Members := True;
Smart_Server := 100;
Smart_Signed := False;
Smart_SuperDetail := False;
{$endif}
SetupSRL;
SMART_ClearCanvas;
MarkTime(T);
box := IntToBox(236,97,271,175);
writeln(CalculateNewPixelShift(box,300,4,2));
writeln('executed in ' + FloatToStr(TimeFromMark(T)/1000.0));
end.
EDIT1: found a bug, fixed it, but still only ever get a pixelshift of 0… hmm
EDIT2: seems to work now. Need some help with efficiency though. A 15x15 pixel square, takes about half a second to complete each repetition. Need to cut that time down to less than 300ms for a 75x150 square…
EDIT3: still working out the bug(s). Flipped the result so it now returns the number of pixels that changed, instead of those that remained the same.
EDIT4: Iv replaced the pixel intersect function, and it is now over 1k times faster. Still getting no pixel-shift every time, even when there is an obvious shift though…
EDIT5: Rewrote to use a boolean array, and it is up to speed.

Sin

2012-03-20 20:53:30

Best of luck ^.^

m34tcode

2012-03-20 20:59:19

Thank you =]. This should hopefully be a great improvement

Valithor

2012-03-20 21:16:49

I'll help with testing. Will get back to you after I've run it a few times.

m34tcode

2012-03-20 21:18:31

If you can find anything wrong in the code please let me know =].

It seems to return 0 always right now, even in the login screen where there should be no pixels that change.

mormonman

2012-03-20 21:54:27

Isn't that exactly what pixelshift does?

m34tcode

2012-03-20 21:58:36

No, Pixel shift, is a function that compares 2 images and returns the number of pixels that changed.

This is similar, but different. This will take an array of pixels, and when a pixel in that array chanegs, it removes it from the array.

this is repeated some number of times and you are left with the pixels that did not change.

the problem with pixelshift is that if you lag it become EXTREMELY unpredictable. This should be fine even with lag, as long as the repetitions paramater is high enough to compensate.

Flight

2012-03-20 22:18:57

So this filters out real pixelshifting and returns the static pixels?

m34tcode

2012-03-20 22:21:24

Exactly, for now anyway. Just realized I should flip that ;]

It will now return the nonstatic pixels. Thanks for that flight :)

EDIT: I reposted the script, with the flipped result. The problem is it always seems to detect that 0 oixels have changed. The place I would think the problem be caused is at line 98, where it checks whether the points and their respective colors are equal. If they are equal, but the test there seems to return the correct results. That line only executes when the two pixels and their colors are equal/within tolerance

Flight

2012-03-20 22:32:46

From: m34tcode
Exactly, for now anyway. Just realized I should flip that ;]

It will now return the nonstatic pixels. Thanks for that flight :)


Sounds good, best of luck to ya mate.

Daniel

2012-03-21 01:10:43

Remove the SMART canvas drawing to speed it up.

Valithor

2012-03-21 09:45:18

SMART hasn't been working for me lately; I've been botting in my browser… So after having deleted all lines relating to SMART and uncommenting the "writeln"s so that I could see it debugging… it … kinda works.

It starts debugging like crazy. Ususally about 50-60 times a second, but almost always the script would return false; even while moving (I tested it while training woodcut).

It returns:= true about once every second, but will continue returning false again. Usually when it returns false I get something similar to the following.

False: (0, 0, 2786423) (5, 9, 2786423)

When it results true one of the first two numbers would have changed. Second one changes more often then the first; when it hits 0 (or what would be 10) the first number increases by 1.

The after everything is all said and done it will debug this. It would debug this even when the "writeln"s were commented.

Completed only 1 of 10. Try increasing the interval
0
Successfully executed.

m34tcode

2012-03-21 14:07:31

Yea, I set it to write the comparison every time it compared.

If the x and y in each parenthesis set are the same, and the last numbers in the parenthesis are colors that are close to each other, it returns true.

That is to show which pixels are being added to the array, the ones that result true.

the 'Completed only 1 of 10. Try increasing the interval' means that there was not enough time given to complete the comparison.

The writeln is also not the part of this that is very slow, it is the 'pixelIntersect' function. I have a better method of calculating the pixels that are the same, and I'm implementing and debugging that now. It 'should' increase the speed of that function 100x.

Thank you for that report, very useful information :)

EDIT: Daniel, it is slow even without the drawing. It's that pixelshift function that needs to be rewritten :P. Think I may be lose though :D

m34tcode

2012-03-21 15:06:35

Im aware this is a double post,

Update

  • Fixed the pixelshift function, and it is now fairly efficient.

Still getting no pixel-shift though… Once that is fixed, this should be a solid function, ready for use and testing =]

putonajonny

2012-03-21 20:06:24

My attempt at making this function: this is by no means an attempt to replace yours, I just liked the sound of the function and thought I would try it:

program new;

{.include SRL/SRL.simba}

function GrabColours(Box : TBox) : array of array of integer;
Var
i, x, y : integer;
begin
SetArrayLength(Result, Box.x2 - Box.x1 + 1);
for i := 0 to high(Result) do
SetArrayLength(Result[i], Box.y2 - Box.y1 + 1);
for x := Box.x1 to Box.x2 do
for y := Box.y1 to Box.y2 do
Result[x - Box.x1][y - Box.y1] := GetColor(x, y);
end;

function InTolerance(Colour1, Colour2, Tolerance : integer) : Boolean;
begin
Result := SimilarColors(Colour1, Colour2, Tolerance);
end;

procedure CompareColours(A1, A2 : array of array of integer; Var B : array of array of Boolean; Tol : integer);
Var
i, j : integer;
begin

for i := 0 to high(A1) do
for j := 0 to high(A1[i]) do
if(B[i][j])then
begin
if(not InTolerance(A1[i][j], A2[i][j], Tol))then
B[i][j] := False;
end;
end;

function CalcPixelShift(Box : TBox; Interval, Time, Tol : Integer) : Integer;
Var
T : integer;
B : array of array of Boolean;
i, x, y : integer;
InitialColours, NewColours : array of array of integer;
begin

InitialColours := GrabColours(Box);

SetArrayLength(B, Box.x2 - Box.x1 + 1);
for i := 0 to high(B) do
SetArrayLength(B[i], Box.y2 - Box.y1 + 1);

for x := 0 to high(B) do
for y := 0 to high(B[x]) do
B[x][y] := True;

MarkTime(T);
While(TimeFromMark(T) < Time)do
begin
NewColours := GrabColours(Box);
CompareColours(InitialColours, NewColours, B, 5);
Wait(Interval);
end;

for x := 0 to high(B) do
for y := 0 to high(B[x]) do
if(not B[x][y])then
inc(Result);

end;

begin
WriteLn(CalcPixelShift(IntToBox(300,300,310,310), 10, 1000, 5));
end.

I would make mine have a time check instead of a wait but I need to go to bed, night!

JuKKa

2012-03-21 20:12:56

if u need more speed, make use of the "Freeze();" and "UnFreeze();" commands.

m34tcode

2012-04-07 03:09:31

The new pixelshift works perfectly. Its fast, 4 runs in less than 2 seconds, from a slow computer.

Reposted it