Results 1 to 7 of 7

Thread: Object finding functions for your review

  1. #1
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default Object finding functions for your review

    Greetings fellow scripters. Warning, TLDR

    The past few weeks I've been working on a library of object finding functions. I am presenting the current work here for community review and feedback. All input welcome!

    This library is not 100% debugged and completed but it it's getting there. I thought it would be smart to get some external opinions and review. The bigger it gets the harder it is to change major design issues. I haven't tested the choose functions yet (and didn't write the chooseWithin function).

    I started working on this for a few reasons.
    1. Most of the functions that accept more than one color do not associate the CTS setting with the color. They take multiple colors but only one CTS spec. This reduces their value since you pretty much always have different hue/saturation per color.
    2. I wanted to work with 'inclusive' searching (where all of the given colors must be found in a certain distance from each other)
    3. I had some confusion on how and when to use different splitting techniques like tpa2atpa and split/cluster and wanted to learn more
    4. The available functions required me to write a lot of the same code repeatedly. I'm a lazy programmer. I would rather see the complexity moved to the data structures and have the code be simplified.


    What I present here is a data structure that fully defines all of the colors for an object (inlcuding their CTS settings). It allows you to attach a filter specification per color. You can also assign a filter specification to the object as a whole so you are able to choose different settings for the colors and the objects. Or leave the color information raw (no filter) and only filter the final result (object).

    Objects can contain a specification for inclusive logic. This is where all of the defined colors must be found within certain distances from each other. I was inispired on this topic by @Runaway @Runaway; in this post. There are a number of other related posts on the topic that I found (a b c). [Why don't mention tags work for me? Argh.]

    I'm going to present some examples first, then describe the code a little afterward. Because examples are fun and the rest is boring!

    Examples:

    Here is the test image used for the examples. It has 8 colors (dark&light blue, dark&light green, dark&light purple, a rusty red, and orange).



    Example 1
    The first example just finds the blue objects in the image.

    Simba Code:
    program example1;
    {$include_once srl-6/srl.simba}
    {$DEFINE TOBJ_DEBUG}
    {$include_once bonsai/libobjfind.simba}

    var
       myObj: TObjFind;
       colFilter: TObjFilterSpec;
       atpa: T2DPointArray;
       searchBox : TBox;
       clW, clH: integer;

    begin
       colFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {min} 80, {max} maxInt);
       myObj.init();
       myObj.addColor(objColor(15106394, {tol} 57, colFilter));   // blues cts0 w/ tol
       getclientdimensions(clW, clH);
       searchBox := intToBox(0, 138, clW-1, clH-1);
       atpa := myObj.findColorsATPA(searchBox);
    end.

    Output for example 1: It returns an ATPA but it only has one row since we only used one color.


    Example 2:
    Same thing but with all the colors in the object. Colors are using CTS 0, 1, and 2.

    Simba Code:
    program example2;
    {$include_once srl-6/srl.simba}
    {$DEFINE TOBJ_DEBUG}
    {$include_once bonsai/libobjfind.simba}

    var
       myObj: TObjFind;
       colFilter: TObjFilterSpec;
       atpa: T2DPointArray;
       searchBox : TBox;
       clW, clH: integer;

    begin
       colFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {min} 80, {max} maxInt);
       myObj.init();
       myObj.addColor(objColor(15106394, {tol} 57, colFilter));   // blues cts0 w/ tol
       myObj.addColor(objColor(3642899, {tol} 38, colorsetting(1), colFilter));   // greens cts1
       myObj.addColor(objColor(9181579, {tol} 15, {hue} 0.01, {sat} 2.09, colFilter));   // purples cts2
       myObj.addColor(objColor(1376392, colFilter));   // rust cts0 pure
       myObj.addColor(objColor(2588671, colFilter));   // orange cts0 pure
       getclientdimensions(clW, clH);
       searchBox := intToBox(0, 138, clW-1, clH-1);
       atpa := myObj.findColorsATPA(searchBox);
    end.

    Output for example 2: Note in this output each color got its own TPA in the ATPA returned


    Example 3:
    Find all the colors, break the output into TBoxes for us. We have to add an object level filter to do boxing.

    Simba Code:
    program example3;
    {$include_once srl-6/srl.simba}
    {$DEFINE TOBJ_DEBUG}
    {$include_once bonsai/libobjfind.simba}

    var
       myObj: TObjFind;
       colFilter, objFilter: TObjFilterSpec;
       tba: TBoxArray;
       searchBox : TBox;
       clW, clH: integer;

    begin
       colFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {min} 80, {max} maxInt);
       objFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {min} 80, {max} maxInt);
       myObj.init(objFilter);
       myObj.addColor(objColor(15106394, {tol} 57, colFilter));   // blues cts0 w/ tol
       myObj.addColor(objColor(3642899, {tol} 38, colorsetting(1), colFilter));   // greens cts1
       myObj.addColor(objColor(9181579, {tol} 15, {hue} 0.01, {sat} 2.09, colFilter));   // purples cts2
       myObj.addColor(objColor(1376392, colFilter));   // rust cts0 pure
       myObj.addColor(objColor(2588671, colFilter));   // orange cts0 pure
       getclientdimensions(clW, clH);
       searchBox := intToBox(0, 138, clW-1, clH-1);
       tba := myObj.findBoxes(searchBox);
    end.

    Output for example 3


    Example 4:
    Same as example 3 but returns centerpoint instead of boxes.

    Simba Code:
    program example4;
    {$include_once srl-6/srl.simba}
    {$DEFINE TOBJ_DEBUG}
    {$include_once bonsai/libobjfind.simba}

    var
       myObj: TObjFind;
       colFilter, objFilter: TObjFilterSpec;
       tpa: TPointArray;
       searchBox : TBox;
       clW, clH: integer;

    begin
       colFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {min} 80, {max} maxInt);
       objFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {min} 80, {max} maxInt);
       myObj.init(objFilter);
       myObj.addColor(objColor(15106394, {tol} 57, colFilter));   // blues cts0 w/ tol
       myObj.addColor(objColor(3642899, {tol} 38, colorsetting(1), colFilter));   // greens cts1
       myObj.addColor(objColor(9181579, {tol} 15, {hue} 0.01, {sat} 2.09, colFilter));   // purples cts2
       myObj.addColor(objColor(1376392, colFilter));   // rust cts0 pure
       myObj.addColor(objColor(2588671, colFilter));   // orange cts0 pure
       getclientdimensions(clW, clH);
       searchBox := intToBox(0, 138, clW-1, clH-1);
       tpa := myObj.findCenters(searchBox);
    end.

    Output for example 4


    Example 5:
    Now we get fancy. Add an inclusive spec and find the boxes where ALL of the colors are found within distance 35 of each other:

    Simba Code:
    program example5;
    {$include_once srl-6/srl.simba}
    {$DEFINE TOBJ_DEBUG}
    {$include_once bonsai/libobjfind.simba}

    var
       myObj: TObjFind;
       colFilter, objFilter: TObjFilterSpec;
       tba: TBoxArray;
       searchBox : TBox;
       clW, clH: integer;

    begin
       colFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {min} 80, {max} maxInt);
       objFilter.init(TObjFilterStyle.CLUSTER, {dist} 35, {min} 80, {max} maxInt);
       myObj.init(objFilter);
       myObj.addColor(objColor(15106394, {tol} 57, colFilter));   // blues cts0 w/ tol
       myObj.addColor(objColor(3642899, {tol} 38, colorsetting(1), colFilter));   // greens cts1
       myObj.addColor(objColor(9181579, {tol} 15, {hue} 0.01, {sat} 2.09, colFilter));   // purples cts2
       myObj.addColor(objColor(1376392, colFilter));   // rust cts0 pure
       myObj.addColor(objColor(2588671, colFilter));   // orange cts0 pure
       myObj.setInclusiveSpec(objInclusiveSpec(TObjInclusiveAlg.EXACT,
          {minDist} 2, {maxDist} 35));

       getclientdimensions(clW, clH);
       searchBox := intToBox(0, 138, clW-1, clH-1);
       tba := myObj.findBoxes(searchBox);
    end.

    Output for example 5


    Example 6:
    Define two objects. One is the blue and purple colors. The second object is has the rust and orange colors. It also has an inclusive spec demanding that both rust and orange are found near each other. Then we find the rust/orange object within the blue/purple object.

    Simba Code:
    program example6
    {$include_once srl-6/srl.simba}
    {$DEFINE TOBJ_DEBUG}
    {$include_once bonsai/libobjfind.simba}

    var
       blueObj, rustObj: TObjFind;
       colFilter, objFilter: TObjFilterSpec;
       searchBox : TBox;
       clW, clH: integer;
       tba: TBoxArray;
       
    begin
       colFilter.init(TObjFilterStyle.CLUSTER, {dist} 2, {minCount} 10, {maxCount} maxInt);
       objFilter.init(TObjFilterStyle.CLUSTER, {dist} 10, {min} 10, {max} maxInt);
       blueObj.init(objFilter);
       rustObj.init(objFilter);
       blueObj.addColor(objColor(13387839, colFilter));   // blue
       blueObj.addColor(objColor(10766755, colFilter));   // purple
       rustObj.addColor(objColor(1376392, colFilter));   // red/brown
       rustObj.addColor(objColor(2588671, colFilter));   // orange
       rustObj.setInclusiveSpec(objInclusiveSpec(TObjInclusiveAlg.EXACT,
          {minDist} 2, {maxDist} 35));
         
       getclientdimensions(clW, clH);
       searchBox := intToBox(0, 0, clW-1, clH-1);

       tba := rustObj.findWithinBoxes(blueObj, searchBox);
    end.

    Output for example 6


    Code Discussion

    Filter Specifiers

    The filter object data is stored in a record. There are functions provided to initialize or create filter objects. There is also a default (null) specification defined.

    Simba Code:
    type TObjFilterSpec = record  {INTERNAL}
    const _NULL_FILTER_SPEC       {A default/blank TObjFilterSpec}

    Filters define how a color or object gets split into subclusters. Each filter has a 'style' indicating which of the splitting functions to use during processing (TPointArray.toATAPA(), .split(), .cluster()). There is an enum defining those.

    Simba Code:
    type TObjFilterStyle = (TOATPA, CLUSTER, SPLIT, NONE);

    They can hold width and height variables or a dist variable. This allows the internal functions to use either of those variations. Filters also have a low/high pixel count indicating how big these clusters should be in order to be retained.

    Here are the TObjFilterSpec type functions to initialize filters.

    Simba Code:
    procedure TObjFilterSpec.init();

    procedure TObjFilterSpec.init(style: TObjFilterStyle; w: integer;
          h: integer; countLow: integer; countHigh: integer); overload;

    procedure TObjFilterSpec.init(style: TObjFilterStyle; distance: integer;
       countLow: integer; countHigh: integer); overload;

    And some functions that create TObjFilterSpec objects on the fly:

    Simba Code:
    function objFilterSpec(): TObjFilterSpec;

    function objFilterSpec(style: TObjFilterStyle; w: integer;
          h: integer; countLow: integer; countHigh: integer): TObjFilterSpec; overload;

    function objFilterSpec(style: TObjFilterStyle; distance: integer;
          countLow: integer; countHigh: integer): TObjFilterSpec; overload;

    Inclusive Specifiers

    An inclusive spec can be attached to the main object. It is also stored in a record with functions to initialize/create it. There is also a default/null instance defined for cases where no inclusive processing will be required.

    Simba Code:
    type TObjInclusiveSpec = record {INTERNAL}
    const _NULL_INCLUSIVE_SPEC      {A default/blank TObjInclusiveSpec}

    The inclusive spec defines the algorithm to be used and a minimum/maximum distance between the colors for them to be considered matches. The algorithm is in an enum and the rest is loaded in the TObjInclusiveSpec.init function.

    Simba Code:
    type TObjInclusiveAlg = (EXACT, RUNAWAY);

    procedure TObjInclusiveSpec.init();

    procedure TObjInclusiveSpec.init(alg: TObjInclusiveAlg; min: integer;
       max: integer); overload;

    These functions will create a TObjInclusiveSpec on the fly:

    Simba Code:
    function objinclusiveSpec(): TObjInclusiveSpec;

    function objinclusiveSpec(alg: TObjInclusiveAlg; min: integer;
       max: integer): TObjInclusiveSpec; overload;

    Colors

    Colors also have their own record, object functions, and functions to create them. The main object holds an array of colors.

    Each color in the array can have any CTS setting and a unique filter specifier, allowing you to define processing with precision.

    Simba Code:
    type TObjColor = record {INTERNAL}
    type TObjColorArray = array of TObjColor;

    TObjColor Initializers:

    Simba Code:
    {CTS0}
    procedure TObjColor.init(col: integer; spec: TObjFilterSpec = _NULL_FILTER_SPEC);

    {CTS0 w/ tolerance}
    procedure TObjColor.init(col: integer; tol: integer;
       spec: TObjFilterSpec = _NULL_FILTER_SPEC); overload;

    {CTS2}
    procedure TObjColor.init(col: integer; tol: integer; hue: extended;
       saturation: extended; spec: TObjFilterSpec = _NULL_FILTER_SPEC); overload;

    {CTS3}
    procedure TObjColor.init(col: integer; tol: integer; sensitivity: extended;
       spec: TObjFilterSpec = _NULL_FILTER_SPEC); overload;

    {any CTS}
    procedure TObjColor.init(col: integer; tol: integer; cs: TcolorSettings;
       spec: TObjFilterSpec = _NULL_FILTER_SPEC); overload;

    Matching creator functions:

    Simba Code:
    function objColor(col: integer; spec: TObjFilterSpec = _NULL_FILTER_SPEC): TObjColor;

    function objColor(col: integer; tol: integer;
       spec: TObjFilterSpec = _NULL_FILTER_SPEC): TObjColor; overload;

    function objColor(col: integer; tol: integer; hue: extended;
       saturation: extended; spec: TObjFilterSpec = _NULL_FILTER_SPEC): TObjColor; overload;

    function objColor(col: integer; tol: integer; sensitivity: extended;
       spec: TObjFilterSpec = _NULL_FILTER_SPEC): TObjColor; overload;

    function objColor(col: integer; tol: integer; cs: TcolorSettings;
       spec: TObjFilterSpec = _NULL_FILTER_SPEC): TObjColor; overload;

    The main object

    Like the rest, the TObjFind type is a record holding the data and a number of functions to initialize them.

    This type also has the "real' processing functions that find the object data for you.

    Simba Code:
    TObjFind = record {INTERNAL}

    Creation / query functions:

    Simba Code:
    procedure TObjFind.init(colArr: TObjColorArray; spec: TObjFilterSpec = _NULL_FILTER_SPEC;  
       inclSpec: TobjInclusiveSpec = _NULL_INCLUSIVE_SPEC; nameStr: string = '');

    procedure TObjFind.init(spec: TObjFilterSpec = _NULL_FILTER_SPEC;  
       inclSpec: TobjInclusiveSpec = _NULL_INCLUSIVE_SPEC; nameStr: string = ''); overload;

    procedure TObjFind.init(col: TObjColor; spec: TObjFilterSpec = _NULL_FILTER_SPEC;
       inclSpec: TobjInclusiveSpec = _NULL_INCLUSIVE_SPEC; nameStr: string = ''); overload;

    procedure TObjFind.addColor(col: TObjColor);
    procedure TObjFind.setColors(colArr: TObjColorArray);
    function TObjFind.getColors(): TObjColorArray;
    procedure TObjFind.setFilterSpec(spec: TObjFilterSpec);
    function TObjFind.getFilterSpec(): TObjFilterSpec;
    procedure TObjFind.setInclusiveSpec(iSpec: TObjInclusiveSpec);
    function TObjFind.getInclusiveSpec(): TObjInclusiveSpec;
    function TObjFind.getLastPoint(): TPoint;
    function TObjFind.getLastBox(): TBox;

    Processing functions:

    Simba Code:
    function TObjFind.findColorsATPA(searchBox: TBox = [-1,-1,-1,-1];
       sortFrom: TPoint = [-1,-1]): T2DPointArray;

    function TObjFind.findColors(searchBox: TBox = [-1,-1,-1,-1];
       sortFrom: TPoint = [-1,-1]): TPointArray;

    function TObjFind.findBoxes(searchBox: TBox = [-1,-1,-1,-1];
       sortFrom: TPoint = [-1,-1]): TBoxArray;

    function TObjFind.findCenters(searchBox: TBox = [-1,-1,-1,-1];
       sortFrom: TPoint = [-1,-1]): TPointArray;

    function TObjFind.choose(searchBox: TBox; sortFrom: TPoint; matchUptext: TStringArray;
       excludeUptext: TStringArray; mouseStyle: integer; choices: TStringArray;
       byBox: boolean = false; pointVariance: integer = 5): boolean;


    function TObjFind.choose(searchBox: TBox; matchUptext: TStringArray;
       excludeUptext: TStringArray; mouseStyle: integer; choices: TStringArray;
       byBox: boolean = false; pointVariance:integer = 5): boolean; overload;

    function TObjFind.findWithinATPA(enclosingObj: TObjFind;
       searchBox: TBox = [-1,-1,-1,-1]; sortFrom: TPoint = [-1,-1]): T2DPointArray;

    function TObjFind.findWithinColors(enclosingObj: TObjFind;
       searchBox: TBox = [-1,-1,-1,-1]; sortFrom: TPoint = [-1,-1]): TPointArray;


    function TObjFind.findWithinBoxes(enclosingObj: TObjFind;
       searchBox: TBox = [-1,-1,-1,-1]; sortFrom: TPoint = [-1,-1]): TBoxArray;

    function TObjFind.findWithinCenters(enclosingObj: TObjFind;
       searchBox: TBox = [-1,-1,-1,-1]; sortFrom: TPoint = [-1,-1]): TPointArray;

    function TObjFind.chooseWithin(enclosingObj: TObjFind; searchBox: TBox;
       sortFrom: TPoint; matchUptext: TStringArray; excludeUptext: TStringArray;
       mouseStyle: integer; choices: TStringArray; byBox: boolean = false;
       pointVariance: integer = 5): boolean;

    Credits:
    Runaway's algorithm used with permission and credited in the code.

    Code link:

    You probably want to remove the include libupdater.simba at the top and the initializer at the end so it won't try to use my autoupdater. The attachment below has that done already.

    http://pastebin.com/raw.php?i=pGwsdnSt
    Attached Images Attached Images
    Attached Files Attached Files

  2. #2
    Join Date
    Oct 2011
    Posts
    805
    Mentioned
    21 Post(s)
    Quoted
    152 Post(s)

    Default

    Really nice release.

    Simba Code:
    myObj.addColor(objColor(15106394, {tol} 57, colFilter));

    In many of my scripts I have been making objects storing all CTS2/3 informations to make color searching more comfortable, but I've never made full include. Now, it looks like something, which I've definitely needed!

    It has include SRL6 line on top, is it just for debug purpose or is it heavily based on SRL functions? (I ask cuz I don't play RS and don't use SRL)

    I see you pointing to some of my old posts. I've also made plugin for it, which does things much more faster then interpreter can do. You may find this interesting: http://villavu.com/forum/showthread....51#post1038051

  3. #3
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default

    Quote Originally Posted by bg5 View Post
    It has include SRL6 line on top, is it just for debug purpose or is it heavily based on SRL functions? (I ask cuz I don't play RS and don't use SRL)

    I see you pointing to some of my old posts. I've also made plugin for it, which does things much more faster then interpreter can do. You may find this interesting: http://villavu.com/forum/showthread....51#post1038051
    It wouldn't take too much to get the SRL out. Obviously, the "choose" functions get cut since they are for picking uptext/menu options. Most of the SRL usage is in the debug printing, all of which have simba alternatives. The biggest issue is I used the SRL TColorSettings stuff to hold the hue/sat/etc. It was there and convenient so I used it but it's not a lot of functionality.

  4. #4
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default

    Bumping for the weekday crowd. Was hoping to get some feedback, positive or negative.

    Thanks!

  5. #5
    Join Date
    Feb 2006
    Location
    Helsinki, Finland
    Posts
    1,395
    Mentioned
    30 Post(s)
    Quoted
    107 Post(s)

    Default

    Ello bonsai,

    This looks like a pretty huge project - Woah!

    I must say, it's always great to see this kind of stuff being developed, especially at this big scale.
    You really have taken this to a next level here! Awesome representation for this project aswell.
    So, really nice work man.

    So, here is some positive feedback by me!

    P.S. I would give you some reputation of this, but I can't yet. :\

    -Jani

  6. #6
    Join Date
    Jan 2007
    Posts
    8,876
    Mentioned
    123 Post(s)
    Quoted
    327 Post(s)

    Default

    This thread has now been sticked!
    Congratulations on release, Bonsai. This work is very good!
    Zyt3x approves!

  7. #7
    Join Date
    May 2007
    Location
    England
    Posts
    4,140
    Mentioned
    11 Post(s)
    Quoted
    266 Post(s)

    Default

    Well deserved sticky! Looks like you've put a lot of work into this, and you've got some fine code at the end of it! Can't wait to see this being utilised to its full potential. Nice work man!

    +rep
    <3

    Quote Originally Posted by Eminem
    I don't care if you're black, white, straight, bisexual, gay, lesbian, short, tall, fat, skinny, rich or poor. If you're nice to me, I'll be nice to you. Simple as that.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •