SRL Archive - General S.M.A.R.T.

Faster Color Searching


BenLand100

2007-07-08 14:52:40

I'm in the process of rewriting the Scar plugin in c++, and I've stumbled across and interesring side effect of using SMART: I have direct memory access to the image. I'm not sure how Scar gets pixel data, but I can only assume it uses the pixels property of a TCanvas, hence why it is almost twice as slow as this method. To do 20,000 GetColors takes on average 250ms. to do 20,000 SmartGetColors takes 130ms on average. I'm going to attempt to write most of scar's searching functions in this way. Hopefully this will allow you to do some more processor intensive searches without the overhead. And for find color I can just skim across the scanlines avoiding unneeded array access math. (Which makes it even faster) I mean really, how can you get any faster than this? :sasmokin:
DelphiExport int __stdcall getColor(int x, int y) {
return image[y*765+x];
}
No comparison what so ever…
Successfully compiled
Testing FindColor...
Result: False:0:0
Started: 70396296
Searched 500 times for $FF in 0,0,764,502
Finished: 70401328
Total Time: 5032
Time per: 10.064
Testing SmartFindColor...
Result: False:-1:-1
Started: 70401328
Searched 500 times for $FF in 0,0,764,502
Finished: 70401859
Total Time: 531
Time per: 1.062
Successfully executed
Successfully compiled
Testing GetColor...
Started: 71333968
Did 500,000 iterations.
Finished: 71338437
Total Time: 4469
Time per: 0.008938
Testing SmartGetColor...
Started: 71338453
Did 500,000 iterations.
Finished: 71341578
Total Time: 3125
Time per: 0.00625
Successfully executed

Smartzkid

2007-07-08 20:01:05

Quite interesting; I doubt this would normally be anything important at all, but when you have 4+ instances of SCAR + RS running at once, it could make a bit of an impact

Thanks again for this amazing piece of..ehm…softwareish java program?

BenLand100

2007-07-08 22:18:34

From: Smartzkid
Quite interesting; I doubt this would normally be anything important at all, but when you have 4+ instances of SCAR + RS running at once, it could make a bit of an impact

Thanks again for this amazing piece of..ehm…softwareish java program?

Think more along the lines of a fast way to find deformed bitmaps, etc. And, are you implying that java isn't a real language? ;)

Anyway, I figured out how to implement all three of scar's similarcolors so it should be easy to do all of the color finding things, even bitmap finding (assuming the bitmap handle is a handle to a HBITMAP ;))

nielsie95

2007-07-09 11:00:22

Wow.. This is really nice.. How much time do you think there will be between Scar and Smart Bitmap finding?

Smartzkid

2007-07-09 12:33:16

Wouldn't that depend on the size of the bitmap?

And whether you're deforming or rotating it, too…

BenLand100

2007-07-09 16:00:26

From: Smartzkid
Wouldn't that depend on the size of the bitmap?

And whether you're deforming or rotating it, too…


It would be, but it would also be a proportinal increase. ie. it the difference would become larget for a larger image.

BenLand100

2007-07-10 22:17:37

This is quite funny I think… Smart found the color closer to the start point… This black wasen't moving either.
Edit: Ran it many more times, The color tends to move around in Scar…
Successfully compiled
Testing SmartFindColorSpiral...
Result: True:265:265
Started: 258214828
Searched 500 times for 0 starting at 250,250 in 0,0,764,502
Finished: 258215875
Total Time: 1047
Time per: 2.094
Testing FindColorSpiral...
Result: True:266:265
Started: 258215875
Searched 500 times for 0 starting at 250,250 in 0,0,764,502
Finished: 258220031
Total Time: 4156
Time per: 8.312
Successfully executed
Then I thought to myself, hmm, what if we search for a color that isn't there?
Successfully compiled
Testing SmartFindColorSpiral...
Result: False:250:250
Started: 258381578
Searched 500 times for $FF starting at 250,250 in 0,0,764,502
Finished: 258385593
Total Time: 4015
Time per: 8.03
Testing FindColorSpiral...
Result: False:250:250
Started: 258385593
Searched 500 times for $FF starting at 250,250 in 0,0,764,502
Finished: 258396781
Total Time: 11188
Time per: 22.376
Successfully executed
I wonder what spiral tollerance is going to be like :sasmokin:

Edit: I want to do bitmap stuff, but i'm having trouble going from a string to a bitmap -.-

Freddy1990

2007-07-11 15:57:29

SCAR uses the default BitBlt API which is one of the few ways to get the bitmap externally…

BenLand100

2007-07-12 03:37:51

HA! So Kaitnieks must have done a lot more to the bitmaps then I had expected, or its a Delphi thing. The pixels were backwards from what a normal (if you can call it normal since it's bottom to top…) windows bitmap. Took me a few hours to figure that one out. Anyway, it currently uses a DC handle rather than the bitmap handle generated by Scar, since I don't know what it is. Thats not a big deal since you can get the DC from a TCanvas and a BITMAP from the DC.
Testing SmartFindBitmap...
Result: True:268:279
Started: 86168250
Searched 1000 times for an 11x21 bitmap
Finished: 86169437
Total Time: 1187
Time per: 1.187
Testing FindBitmap...
Result: True:268:279
Started: 86169453
Searched 1000 times for an 11x21 bitmap
Finished: 86178703
Total Time: 9250
Time per: 9.25
Also Freddy, you may (or may not) want to look into using memory whenever possible. Its not avaliable for all/most windows, but all off screen bitmaps have a memory space which is significantly faster than other methods. This is C but I assume it will translate into Delphi easily enough… I might even take a crack at it ;) Anyway, the BITMAP structure has the width, height, and pointer to the pixels in memory.

 BITMAP* __stdcall bmpdata(int hdc) {
HBITMAP hbitmap = (HBITMAP) GetCurrentObject((HDC)hdc, OBJ_BITMAP);
BITMAP* bmp = (BITMAP*) malloc(sizeof(BITMAP));
GetObject((HBITMAP)hbitmap,sizeof(BITMAP),bmp);
if ((*bmp).bmBits == NULL) throw 1;
return bmp;
}

//Did this in the message box :)
function bmpdata(dc: Cardinal): ^BITMAP;
var
bitmap: Cardinal;
begin
//OBJ_BITMAP is a constant, I assume the name is the same.
bitmap:= GetCurrentObject(dc, OBJ_BITMAP);
//Might have to pass a Pointer in place of result then assign the value to result
GetObject(bitmap,sizeof(BITMAP),result);
//Can't remember Delphi's derefrence operator...
if (result^).bmBits = nil then raise Exception.create('');
end;
Edit: Hehe, added bounds checking so it dosen't search areas where the bitmap couldn't be (ie. the right side and bottom) and improved my time by a few tenths of a millisecond :f:
Testing SmartFindBitmap...
Result: True:268:279
Started: 87608390
Searched 1000 times for an 11x21 bitmap
Finished: 87609359
Total Time: 969
Time per: 0.969
Testing FindBitmap...
Result: True:268:279
Started: 87609359
Searched 1000 times for an 11x21 bitmap
Finished: 87618703
Total Time: 9344
Time per: 9.344
Edit: Now, deformed will be a pain to code effeciantly however I think once I start it will fall together. I'll need to work out an algorithm for masks, shouldn't be too hard. With DTM's I'll run into the problem with not knowing what a DTM handle is, so I'll take a crack at the strings and override all of the dynamic methods. Whats left… Ah text. That's going to be a pain. Also, I found this funny (in the help file): "Returns all colors on the minimap that are similar to the entered color, using an advanced color comparison method." The model that was used would be helpful: HSL, HSV, LAB, XYZ (CMYK or RGB ;)) But I guess its part of the Scar black box like whatever compression method is used on the bitmap data…

Edit: That reminds me, why dosen't Scar return the HBITMAP of the bitmap when it is created? The HBITMAP's BITMAP structure contains the width, height, and color data that Scar needs, plus it makes it easy to pass to a plugin. Furthermore, the HBITMAP in Delphi is the handle property of a TBitmap, and its unique. Whatever is returned is a valid HBITMAP, but its not the right one. Not even the size is correct, my 11x21 comes out to 0x640. Might be a memory leak somewhere… (If its not a leak and its structured that way for a reason, please fill me in :)) Anywho, i'm ranting ;)

Edit: Let me restate that, its not a valid HBITMAP, windows just returns a random bitmap when you give it a random handle…

Freddy1990

2007-07-20 16:29:23

Myes… well you know how i think ;)
However… the only bitmap I would need to access directly from the memory is the actual image of the client which I assume isn't a bitmap in the memory… or is it?

BenLand100

2007-07-21 19:01:37

It may be, it may not be, you can check however. You can retrieve the selected object out of a DC and use GetObject on that HBITMAP to get the BITMAP construct that contains a memory pointer that is non null (nil) if it is in the memory ;)

Freddy1990

2007-07-22 08:33:03

Doesn't work for windows, only for regular bitmaps in the memory

EDIT: This gives me an idea though, I'm going to modify this function so that it'll allow you to load a bitmap from a DC in the memory straight into SCAR ^^

EDIT2:
There we go: function BitmapFromMem(Dc: HDC): Integer;

Ben, I also changed the DC functions again, now they return a HDC, well LongWord, same thing… Instead of the annoying Extended :) And I added HDC and HBITMAP as types to SCAR…
And finally I'm gonna see if I can add in a function to return the HBITMAP of the bitmaps :)

BenLand100

2007-07-22 21:46:17

From: Freddy1990
Doesn't work for windows, only for regular bitmaps in the memory

Have you attempted to turn off hardware acceleration on your graphics card? You should be able to disable hardware bitmaps somewhere, then all bitmaps (including those used for the dc's of windows) will be in the memory. ;)

Freddy1990

2007-07-23 08:06:25

Heh, then everyone who wants to use SCAR has to turn off hardware acelleration? that seems a bit exagerated :)

EDIT: Ok, Benland, because you so like to puch me I threw out kaitnieks' FindColor and FindColorTolerance and wrote new ones from scratch and I managed to pinch off a few ms…

The average exec speed of FindColor in SCAR 3.11 is: 8,0752ms.
The average exec speed of FindColor in SCAR 3.12 is: 4,4622ms.

That's for running the function 5000 times in the entire client, searching for a non-existing color.

I'll post the benchmarks for FindColorTolerance once I benchmarked it…

(Do note that the reason that I can't get as fast as SMART is because I can't get the image directly, I have to copy it from the screen first which is time consuming)

EDIT:
Search 1000 times for non-existing color in client with tolerance 1
The average exec speed of FindColorTolerance in SCAR 3.11 is: 30,453ms.
The average exec speed of FindColorTolerance in SCAR 3.12 is: 27,359ms.

BenLand100

2007-07-23 19:54:15

From: Freddy1990
(Do note that the reason that I can't get as fast as SMART is because I can't get the image directly, I have to copy it from the screen first which is time consuming)

GetDIBits might be a better bet (I've been told its faster than BitBlt, plus it copies to memory), however Microsoft is vague about if it works on non memory bitmaps. Also, I've found a way to do everything SMART does without using any Java… Its a dirty little trick with the same principle as SMART, but it would require no changes if it were built into Scar's event dispatching system, would work for any program also (non-Java and Java) I'll get back to you on that when I've messed with it more. ;)

Freddy1990

2007-07-24 04:03:54

I didn't know that GetDiBits actually retrieved the bitmap, I thought it converted a bitmap into a dib handle to use for analysing… I'll take a look at that then