Log in

View Full Version : Help, distance between atpas.



johnbrown8976
05-01-2012, 03:13 AM
hi,
I was trying to detect an object with multiple colors using ATPA.

Scenario: The object has 3 colors. I calculated the ATPA of each 3 colors. Now, I want to check if all three colors are close to each other (within specified distance). I am having a hard time how to do it.

Code updated. Thanks ggzz.

program new;
{$i srl/srl.simba}

var
maxDistance: Integer;
i, x, y, color, tol : Array[0..2] of Integer;
tpa : Array[0..2] of TPointArray;
atpa: Array[0..2] of T2DPointArray;

begin
if not FindColorsTolerance(tpa[0], color[0], MSX1, MSY1, MSX2, MSY2, tol[0]) then
exit;
if not FindColorsTolerance(tpa[1], color[1], MSX1, MSY1, MSX2, MSY2, tol[1]) then
exit;
if not FindColorsTolerance(tpa[2], color[2], MSX1, MSY1, MSX2, MSY2, tol[2]) then
exit;

atpa[0] := SplitTPA(tpa[0], 10);
atpa[1] := SplitTPA(tpa[1], 10);
atpa[2] := SplitTPA(tpa[2], 10);

//first ATPA for loop
for i[0]:=0 to High(atpa[0]) do
begin
tpa[0] := atpa[0][i[0]];
if MiddleTPAEx(tpa[0], x[0], y[0]) then
begin
//Second ATPA for loop
for i[1]:=0 to High(atpa[1]) do
begin
tpa[1] := atpa[1][i[1]];
if MiddleTPAEx(tpa[1], x[1], y[1]) then
begin
if not (Distance(x[0], y[0], x[1], y[1])<maxDistance) then
exit;
//Third ATPA for loop
for i[2]:=0 to High(atpa[2]) do
begin
tpa[2] := atpa[2][i[2]];
if MiddleTPAEx(tpa[2], x[2], y[2]) then
begin
if not (Distance(x[0], y[0], x[2], y[2])<maxDistance) or (Distance(x[1], y[1], x[2], y[2])<maxDistance) then
exit
else
writeln('Found the Perfect TPoint P(' + IntToStr(x[2]) + ', ' + IntToStr(y[2]) + ')');
end;
end;
end;
end;
end;
end;
end.

Abu
05-01-2012, 04:45 AM
Hmmm, AFAIK it won't search for all three colours; it'll stop searching once it finds one of the colours.

This also means that it will always return one set of TPA's so there is no need to have TPA[0], [1] and [2].

Blank Check
05-01-2012, 04:45 AM
Search first colors TPA, split TPA into ATPA.

Go through ATPA from first color's bounds to search for presence of 2nd color.

If successful continue to check for 3rd colors presence within bounds, if not go back to looping through first color.

johnbrown8976
05-01-2012, 05:26 AM
Hmmm, AFAIK it won't search for all three colours; it'll stop searching once it finds one of the colours.

This also means that it will always return one set of TPA's so there is no need to have TPA[0], [1] and [2].
hi, sorry for the confusion.
I have NOT in each IF statement

If it cannot find first color, exit
Else If it finds the first color, continue...


if not FindColorsTolerance(tpa[0], color[0], MSX1, MSY1, MSX2, MSY2, tol[0]) then
exit;
if not FindColorsTolerance(tpa[1], color[1], MSX1, MSY1, MSX2, MSY2, tol[1]) then
exit;
if not FindColorsTolerance(tpa[2], color[2], MSX1, MSY1, MSX2, MSY2, tol[2]) then
exit;

Brandon
05-01-2012, 05:39 AM
Hmmm, AFAIK it won't search for all three colours; it'll stop searching once it finds one of the colours.

This also means that it will always return one set of TPA's so there is no need to have TPA[0], [1] and [2].

lol I'd like to have some of what your having.. Array[0..2] of TPointArray;

is a 2D-array of points There IS a need for the index to be passed and it will NOT stop searching -__-

It will look for the first colour, add all the locations to the index 1 of that atpa then the second will do it to the next index.

@OP just do

MiddleTPA(TPA[I], X, Y)
MiddleTPA(TPA[J], PX, PY)

Distance(X, Y, PX, PY);

For three of them, your going to have to do that three times. One for each side of the triangle a pair forms.

For Inception Objects.. Aka Objects that have more than 3 colours within an area, I use:

type
ObjectInfo = record
Color: TIntegerArray;
Tolerance: TIntegerArray;
Speed: TExtendedArray;
Width, Height, InnerWidth, InnerHeight: Integer;
end;

Function ReturnObjectInfo: ObjectInfo;
begin
Result.Color:= [2635334, 13817304, 10985374]; //Brown, White, PrayerBook.. Colors..
Result.Tolerance:= [11, 8, 11]; //Tolerances For Each Of The Above Colors.
Result.Speed:= [0.06, 0.15, 1.05, 1.06, 0.17, 0.22]; //Hue, Sat For Each Color.
Result.Width:= 75; //Width of the entire object
Result.Height:= 51; //Height of the entire object
Result.InnerWidth:= 45; //Approx width of second color
Result.InnerHeight:= 70; //Approx height of second color
end;

Function FindObjectInception(Uptexts: TStringArray): TPoint;
var
Object: ObjectInfo;
CTS, L, I, K, J: Integer;
TPA: TPointArray;
ATPA, ATPA2, ATPA3, ATPA4: T2DPointArray;
B, B2: TBox;
Bool: Boolean;
begin
Bool:= False;
Result:= Point(-1, -1);
CTS:= GetColorToleranceSpeed;
ColorToleranceSpeed(2);
Object:= ReturnObjectInfo;

SetColorSpeed2Modifiers(Object.Speed[0], Object.Speed[1]);
FindColorsTolerance(TPA, Object.Color[0], MSX1, MSY1, MSX2, MSY2, Object.Tolerance[0]);
ColorToleranceSpeed(CTS);
SetColorSpeed2Modifiers(0.02, 0.02);

If Length(TPA) < 1 then
exit;

ATPA:= TPAToATPAEx(TPA, Object.Width, Object.Height);
SortATPAFromSize(ATPA, 100, False);
L := High(ATPA);
SetArrayLength(ATPA2, L+1);
For I := 0 to L do
begin
B := GetTPABounds(ATPA[I]);
with B do
begin
SetColorSpeed2Modifiers(Object.Speed[2], Object.Speed[3]);
FindColorsTolerance(ATPA2[I], Object.Color[1], B.X1, B.Y1, B.X2, B.Y2, Object.Tolerance[1]);
ColorToleranceSpeed(CTS);
SetColorSpeed2Modifiers(0.02, 0.02);

if (Length(ATPA2[I]) < 1) or (Length(ATPA2) < 1) then
Continue;

begin
ATPA3:= TPAToATPAEx(ATPA2[I], Object.InnerWidth, Object.InnerHeight);
K := High(ATPA2[I]);
SetArrayLength(ATPA4, K+1);
For J:= 0 To K do
begin
B2 := GetTPABounds(ATPA2[J]);
with B2 do
begin
ColorToleranceSpeed(2);
SetColorSpeed2Modifiers(Object.Speed[4], Object.Speed[5]);
FindColorsTolerance(ATPA4[J], Object.Color[2], B2.X1, B2.Y1, B2.X2, B2.Y2, Object.Tolerance[2]);
ColorToleranceSpeed(CTS);
end;

Bool:= (Length(ATPA4[J]) > 0);
If (Bool) then
begin
MiddleTPAEx(ATPA4[J], Result.X, Result.Y);
MMouse(Result.X, Result.Y, 0, 0);
if WaitUptextMulti(UpTexts, 600) then
begin
GetMousePos(Result.X, Result.Y);
Exit
end else
Result:= Point(-1, -1);
end;
end;
end;
end;
end;
end;

It finds an object given 3 colours, three tolerances and 3 sets of hue's and sats.. all found from ACA.
First colour is the outer colour or area colour.. Second colour is one found within that. Last colour is the one found within the second.

Example a guilded altar has a brown outer colour. Inside that, there is a white marble colour. Inside the marble colour, there is gold OR there is the prayer book grey colour.

Another example is the LRC Bank. The first colour would be black because the Deposit box sits in a black area. Next colour would be dark brown which is the pulley colour. The next colour is tan brown and that's the crate inside the pulley. Get it?

So: Tan inside Brown inside black = Crate inside pulley inside black area.

for the altar it was Book inside white area inside brown outer colour.

Hope that helps.

johnbrown8976
05-01-2012, 05:40 AM
Search first colors TPA, split TPA into ATPA.

Go through ATPA from first color's bounds to search for presence of 2nd color.

If successful continue to check for 3rd colors presence within bounds, if not go back to looping through first color.

Thanks for your idea. At first, I thought your idea would work for me. After a little observation, I found that it would not work for me.
BECAUSE:
In my situation, the second color TPA is not inside the first color ATPA bounds, it is closer to it, meaning at a distance of 20, 50 or something.

I am assuming that this is what you tried to propose.
I really appreciate your help.

program new;
var
x, y, i, j: Integer;
color, tol : Array[0..2] of Integer;
tpa : Array[0..2] of TPointArray;
atpa: Array[0..2] of T2DPointArray;
box: TBox;

begin
if not FindColorsTolerance(tpa[0], color[0], MSX1, MSY1, MSX2, MSY2, tol[0]) then
exit;
atpa[0] := SplitTPA(tpa[0], 10);
box := GetATPABounds(atpa[0]);

if not FindColorsTolerance(tpa[1], color[1], box.X1, box.Y1, box.X2, box.Y2, tol[1]) then
exit;
atpa[1] := SplitTPA(tpa[1], 10);
box := GetATPABounds(atpa[1]);

if not FindColorsTolerance(tpa[2], color[1], box.X1, box.Y1, box.X2, box.Y2, tol[1]) then
exit;
atpa[2] := SplitTPA(tpa[2], 10);

for i:=0 to High(atpa[2]) do
begin
tpa[2] := atpa[2][i];
if MiddleTPAEx(tpa[2], x, y) then
begin
// Check distance with TPAs of other ATPAs
// I am lost here
end;
end;
end.

johnbrown8976
05-01-2012, 06:11 AM
lol I'd like to have some of what your having.. Array[0..2] of TPointArray;

is a 2D-array of points There IS a need for the index to be passed and it will NOT stop searching -__-

It will look for the first colour, add all the locations to the index 1 of that atpa then the second will do it to the next index.

@OP just do

MiddleTPA(TPA[I], X, Y)
MiddleTPA(TPA[J], PX, PY)

Distance(X, Y, PX, PY);

For three of them, your going to have to do that three times. One for each side of the triangle a pair forms.

For Inception Objects.. Aka Objects that have more than 3 colours within an area, I use:

~Hidden~

It finds an object given 3 colours, three tolerances and 3 sets of hue's and sats.. all found from ACA.
First colour is the outer colour or area colour.. Second colour is one found within that. Last colour is the one found within the second.

Example a guilded altar has a brown outer colour. Inside that, there is a white marble colour. Inside the marble colour, there is gold OR there is the prayer book grey colour.

Another example is the LRC Bank. The first colour would be black because the Deposit box sits in a black area. Next colour would be dark brown which is the pulley colour. The next colour is tan brown and that's the crate inside the pulley. Get it?

So: Tan inside Brown inside black = Crate inside pulley inside black area.

for the altar it was Book inside white area inside brown outer colour.

Hope that helps.

Your code looks awesome. I really appreciate your help. However, in my situation, the colors are not inside each other, one is attached to another one or at a distance of 20-30 from each other. I liked the triangle sides idea you proposed, I would like to confirm if this is what you proposed before.

program new;
{$i srl/srl.simba}

var
maxDistance: Integer;
i, x, y, color, tol : Array[0..2] of Integer;
tpa : Array[0..2] of TPointArray;
atpa: Array[0..2] of T2DPointArray;

begin
if not FindColorsTolerance(tpa[0], color[0], MSX1, MSY1, MSX2, MSY2, tol[0]) then
exit;
if not FindColorsTolerance(tpa[1], color[1], MSX1, MSY1, MSX2, MSY2, tol[1]) then
exit;
if not FindColorsTolerance(tpa[2], color[2], MSX1, MSY1, MSX2, MSY2, tol[2]) then
exit;

atpa[0] := SplitTPA(tpa[0], 10);
atpa[1] := SplitTPA(tpa[1], 10);
atpa[2] := SplitTPA(tpa[2], 10);

//first ATPA for loop
for i[0]:=0 to High(atpa[0]) do
begin
tpa[0] := atpa[0][i[0]];
if MiddleTPAEx(tpa[0], x[0], y[0]) then
begin
//Second ATPA for loop
for i[1]:=0 to High(atpa[1]) do
begin
tpa[1] := atpa[1][i[1]];
if MiddleTPAEx(tpa[1], x[1], y[1]) then
begin
if not (Distance(x[0], y[0], x[1], y[1])<maxDistance) then
exit;
//Third ATPA for loop
for i[2]:=0 to High(atpa[2]) do
begin
tpa[2] := atpa[2][i[2]];
if MiddleTPAEx(tpa[2], x[2], y[2]) then
begin
if not (Distance(x[0], y[0], x[2], y[2])<maxDistance) or (Distance(x[1], y[1], x[2], y[2])<maxDistance) then
exit
else
writeln('Found the Perfect TPoint P(' + IntToStr(x[2]) + ', ' + IntToStr(y[2]) + ')');
end;
end;
end;
end;
end;
end;
end.

Abu
05-01-2012, 06:19 AM
hi, sorry for the confusion.
I have NOT in each IF statement

If it cannot find first color, exit
Else If it finds the first color, continue...


Oh no I knew that, in fact I was making exactly that point:

Hmmm, AFAIK it won't search for all three colours; it'll stop searching once it finds one of the colours.


However I was wrong about not using Array of TPointArray and Array of T2DPointArray. My bad :redface:

But hey, I did say As Far As I Know :p

Brandon
05-01-2012, 09:17 AM
Not sure how the previous function posted wouldn't work but here you choose between the three functions below..


Function FindObjectNearObject: TPoint;
var
Tol, Col: TIntegerArray;
FinalTPA: TPointArray;
TPAs: T2DPointArray;
begin
FindColorsTolerance(TPAs[0], Col[0], MSX1, MSY1, MSX2, MSY2, Tol[0]);
FindColorsTolerance(TPAs[1], Col[1], MSX1, MSY1, MSX2, MSY2, Tol[1]);
FindColorsTolerance(TPAs[2], Col[2], MSX1, MSY1, MSX2, MSY2, Tol[2]);

if (Length(TPAs[0]) < 1) or (Length(TPAs[1]) < 1) or (Length(TPAs[2]) < 1) then
Exit;

FinalTPA:= CombineTPA(CombineTPA(TPAs[0], TPAs[1]), TPAs[2]);

Result:= MiddleTPA(FinalTPA);
end;

Function TriangleObjectMidpoint: TPoint;
var
Tol, Col: TIntegerArray;
TPAs: T2DPointArray;
TPA: TPointArray;
begin
FindColorsTolerance(TPAs[0], Col[0], MSX1, MSY1, MSX2, MSY2, Tol[0]);
FindColorsTolerance(TPAs[1], Col[1], MSX1, MSY1, MSX2, MSY2, Tol[1]);
FindColorsTolerance(TPAs[2], Col[2], MSX1, MSY1, MSX2, MSY2, Tol[2]);

if (Length(TPAs[0]) < 1) or (Length(TPAs[1]) < 1) or (Length(TPAs[2]) < 1) then
Exit;

SetLength(TPA, 3);
TPA[0]:= MiddleTPA(TPAs[0]);
TPA[1]:= MiddleTPA(TPAs[1]);
TPA[2]:= MiddleTPA(TPAs[2]);

Result:= Point(Round((TPA[0].X + TPA[1].X + TPA[2].X) div 3), Round((TPA[0].Y + TPA[1].Y + TPA[2].Y) div 3));
end;

Function TriangleATPAsMidpoint: TPoint;
var
I, J, K, L, LL, LLL, Minimum: Integer;
Tol, Col: TIntegerArray;
TPAs, ATPA, ATPA2, ATPA3: T2DPointArray;
PointsA, PointsB, PointsC: TPointArray;
begin
FindColorsTolerance(TPAs[0], Col[0], MSX1, MSY1, MSX2, MSY2, Tol[0]);
FindColorsTolerance(TPAs[1], Col[1], MSX1, MSY1, MSX2, MSY2, Tol[1]);
FindColorsTolerance(TPAs[2], Col[2], MSX1, MSY1, MSX2, MSY2, Tol[2]);

if (Length(TPAs[0]) < 1) or (Length(TPAs[1]) < 1) or (Length(TPAs[2]) < 1) then
Exit;

ATPA:= SplitTPA(TPAs[0], 10);
ATPA2:= SplitTPA(TPAs[1], 10);
ATPA3:= SplitTPA(TPAs[2], 10);

L:= High(ATPA);
LL:= High(ATPA2);
LLL:= High(ATPA3);

if (L < 1) or (LL < 1) or (LLL < 1) then
Exit;

For I:= 0 To L do
begin
SetLength(PointsA, I + 1);
PointsA[I]:= MiddleTPA(ATPA[I]);
end;

For I:= 0 To LL do
begin
SetLength(PointsB, I + 1);
PointsB[I]:= MiddleTPA(ATPA2[I]);
end;

For I:= 0 To LLL do
begin
SetLength(PointsC, I + 1);
PointsC[I]:= MiddleTPA(ATPA3[I]);
end;

L:= High(PointsA);
LL:= High(PointsB);
LLL:= High(PointsC);

Minimum:= Min(Min(L, LL), LLL);

For I:= 0 To Minimum do
begin
if (Distance(PointsA[I].X, PointsA[I].Y, PointsB[I].X, PointsB[I].Y) < 20) then
For J:= 0 To Minimum do
if (Distance(PointsB[J].X, PointsB[J].Y, PointsC[J].X, PointsC[J].Y) < 20) then
For K:= 0 To Minimum do
if (Distance(PointsC[K].X, PointsC[K].Y, PointsA[K].X, PointsA[K].Y) < 20) then
begin
Result:= Point(Round((PointsA[I].X + PointsB[J].X + PointsC[K].X) div 3), Round((PointsA[I].Y + PointsB[J].Y + PointsC[K].Y) div 3));
Exit;
end;
end;

Result:= TriangleObjectMidpoint; //or Point(-1, -1);
end;

bg5
05-01-2012, 03:18 PM
:)
This doesn't work on middleTPA ,but iterate througth all points in tpa.

// Result is TPA of that points from tpa1 ,which have in neighborhood any point from tpa2. - by beginner5
function AND_TPA (tpa1 , tpa2 :TpointArray ; MinDist ,MaxDist : extended) : TPointArray;
var
a : integer;
temp_tpa1 :tPointarray;
begin
Setlength(Result,0);
for a:=0 to High(tpa2) do
begin
temp_tpa1 := tpa1; // Don't want FilterPointsDist overwrite tpa1

FilterPointsDist(temp_tpa1,MinDist,MaxDist,tpa2[a].x,tpa2[a].y);
// writetpa('temp',temp_tpa1);

CombineTPAWrap(Result,temp_tpa1,Result);
//writetpa('Res',Result);
end;
ClearSamePoints(Result);
end;

Example:


FindColorsTolerance(TPA1, Color1, MSX1, MSY1, MSX2, MSY2, Tol); // first color of object
FindColorsTolerance(TPA2, Color2, MSX1, MSY1, MSX2, MSY2, Tol); //second color of object

ResultTPA := AND_TPA(TPA1,TPA2,0,10); // ResultTPA contains pixels of color1 which are close to pixels of color2 in range of 10.


If it's a bit slow ,you can make it faster adding RAaSTPAEx (it cuts length of TPAs) ,example:

FindColorsTolerance(TPA1, Color1, MSX1, MSY1, MSX2, MSY2, Tol); // first color of object
RAaSTPAEx(TPA1,3,3);
FindColorsTolerance(TPA2, Color2, MSX1, MSY1, MSX2, MSY2, Tol); //second color of object
RAaSTPAEx(TPA2,3,3);

ResultTPA := AND_TPA(TPA1,TPA2,0,10); // ResultTPA contains pixels of color1 which are close to pixels of color2 in range of 10.