Skip to content
This repository has been archived by the owner on Jun 10, 2018. It is now read-only.

[fix] two issues with find_bitmap #74

Closed
donjan opened this issue Jun 19, 2015 · 1 comment
Closed

[fix] two issues with find_bitmap #74

donjan opened this issue Jun 19, 2015 · 1 comment

Comments

@donjan
Copy link

donjan commented Jun 19, 2015

First issue.
Searching with haystack.find_bitmap(needle, tolerance) and 0<tolerance<<1 doesn't work.
The problem is in MMRGBHexSimilarToColor() at src/rgb.h:98 where the differences are stored as uint8_t, but we need to handle a range of (-255, -255).
uint wrapping doesn't work because a very similar h1 - h2, e.g. 21 - 23, gets stored as d1=254, which fails the search for small tolerance.
The fix is to use a signed integer that supports the range (i.e. int), and due to simplicity I won't bother putting a fork online and sending a pulling request. Here's the diff:

@@ -117,18 +95,30 @@
    if (tolerance <= 0.0f) {
        return h1 == h2;
    } else {
-       uint8_t d1 = RED_FROM_HEX(h1) - RED_FROM_HEX(h2);
-       uint8_t d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2);
-       uint8_t d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2);
+       int d1 = RED_FROM_HEX(h1) - RED_FROM_HEX(h2);
+       int d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2);
+       int d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2);
        return sqrt((d1 * d1) +
                    (d2 * d2) +
                    (d3 * d3)) <= (tolerance * 442.0f);
    }
 }

Also the same should be done for the MMRGBColorEqualToColor() higher up.

Second issue.
The find_bitmap function is internally 0-start-index based, but returns (1,1) if the match occurs at the very beginning, which implies autopy.bitmap to be 1-start-index based. Yet Bitmap.get_portion() appears to work with 0-start-index (side note: the documentation in this regard is lacking).
Easiest way to check is by searching for itself:

img = autopy.bitmap.Bitmap.open("test.png")
pos = img.find_bitmap(img, 0.01)
img.get_portion(pos, (img.width, img.height)).save('match.png')

pos is (1,1) and the last line throws a ValueError: Portion out of bounds
If we get_portion(pos, (img.width-1, img.height-1)) the resulting match.png is wrong (1 pixel too small in each direction).
The simple fix is in findBitmapInRectAt at src/bitmap_find.c:89 to increment pointOffset after assigning, not before (EDIT) not increment pointOffset before returning. Again due to simplicity here's just the diff:

@@ -86,9 +86,9 @@
        while (pointOffset.x <= scanWidth) {
            /* Check offset in |haystack| for |needle|. */
            if (needleAtOffset(needle, haystack, pointOffset, tolerance)) {
-               ++pointOffset.x;
-               ++pointOffset.y;
                *point = pointOffset;
                return 0;
            }

This gives the correct result. It changes postconditions though, so the proper thing to do would be to define the coordinate start somewhere (documentation?) and be consistent about it.

Conclusion.
I hope these two "patches" get accepted quickly, as I have a slightly improved fuzzy matching (which requires some more changes) that depends on them.

@msanders
Copy link
Collaborator

msanders commented May 2, 2018

This should be fixed now in the latest version.

@msanders msanders closed this as completed May 2, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants