BitmapData#compare ??!?

44 posts

Flag Post

BitmapData#compare is quite weird.

From the documentation:

Compares two BitmapData objects. If the two BitmapData objects have the same dimensions (width and height), the method returns a new BitmapData object, in which each pixel is the “difference” between the pixels in the two source objects:

If two pixels are equal, the difference pixel is 0×00000000.

If two pixels have different RGB values (ignoring the alpha value), the difference pixel is 0xRRGGBB where RR/GG/BB are the individual difference values between red, green, and blue channels (the pixel value in the source object minus the pixel value in the otherBitmapData object). Alpha channel differences are ignored in this case.

If only the alpha channel value is different, the pixel value is 0xZZFFFFFF, where ZZ is the difference in the alpha values (the alpha value in the source object minus the alpha value in the otherBitmapData object).

Okay, slightly strange, but not that bad. However:

The result of the compare() method is a new BitmapData object with each pixel showing the difference in the alpha values between the two bitmaps.

If the BitmapData objects are equivalent (with the same width, height, and identical pixel values), the method returns the number 0.

If the widths of the BitmapData objects are not equal, the method returns the number -3.

If the heights of the BitmapData objects are not equal, but the widths are the same, the method returns the number -4.

Anyone want to take a guess at explaining why in the world this method works/is designed like this?

 
Flag Post

I’m not sure why they thought this was a good idea to implement. Perhaps because they expected someone to want to check all at the same time, instead of calling several functions in a row to get the same results.

 
Flag Post

It’s silly. I’m sure there are a million situations where developers need to do all kinds of strange comparisons and operations, but they should just let the developers code it themselves, rather than bloat up the Flash Player with native functions that almost never get used.

 
Flag Post

Remember, it is a native function, and that means that most likely this is used by other functions.

 
Flag Post
Originally posted by Secretmapper:

Remember, it is a native function, and that means that most likely this is used by other functions.

hmmm, true, but at the same time native functions don’t call each other in the same way that AS3 code calls a native function. There would be too much cost in the overhead. So there is definitely effort and space used on making it accessible to AS3.

 
Flag Post
Originally posted by Secretmapper:

Remember, it is a native function, and that means that most likely this is used by other functions.

And that also makes it perform faster which could be useful to AS3 devs. I still think the return -3 and -4 for unequal width/height seems pretty strange though, wonder if it used to return -1 and -2 for other things?

 
Flag Post
Originally posted by BobTheCoolGuy:
Originally posted by Secretmapper:

Remember, it is a native function, and that means that most likely this is used by other functions.

And that also makes it perform faster which could be useful to AS3 devs. I still think the return -3 and -4 for unequal width/height seems pretty strange though.

Oh, a winner is me! :D Looked up the AS2 documentation. In AS2, all of the AS3 returns were the same plus:

If no argument is passed or if the argument is not a BitmapData object, the method returns -1.

If either BitmapData object has been disposed of, the method returns -2.

 
Flag Post

OK so it’s there in AS3 because it was there in AS2… that still doesn’t tell us why it was in AS2 in the first place. What could possibly use that. Filters maybe?

 
Flag Post

What could possibly use that.

A lot of things.

 
Flag Post

Name one.

 
Flag Post

The result of the compare() method is a new BitmapData object with each pixel showing the difference in the alpha values between the two bitmaps.

^^ this. Remember that it also returns a bitmapdata object, not just esoteric numbers.

 
Flag Post

Yea, and what’s the practical use of that? Obviously you can argue that any function has one practical application which is to return its output when called. You might even think it’s a clever retort but it’s just a tautology.

So in the case of compare(), the result can be an esoteric BitmapData object, not just an esoteric int.* Still, look at what ends up in the Bitmapdata: Either A1 + (RGB1 – RGB2) if RGB1 != RBG2 or (A1 – A2) + 0xFFFFFF if RGB1 == RGB2 so in other words if pixel1 is yellow (0xFFFFFF00) and pixel2 is almost yellow (0xFFFEFE00) you get solid (almost) black (0xFF010100) but if both pixels are pure yellow you get transparent (0×00FFFFFF).

Interestingly, if pixel1 is pure white, you get the same output (0xFFFFFFFF) whether pixel2 is solid black (0xFF000000) or transparent white (0×00FFFFFF), but not if pixel2 is transparent anything else. When could that possibly be desirable behavior?

All these weird behaviors make the method so specialized in its application that I, again, challenge you to name one practical application for it.

*: And do you really want to get into how horrible it is to have a function that can return values of type int or BitmapData depending on what its input was? That’s terrible, horrible coding practice. If someone posted a thread in here with a function that does that people would ignore their actual question and rip them a new one for it, with good reason.

 
Flag Post

@Ace_Blue:
I agree, the return value scheme is what really through me for a loop. I saw it used in a library once though to check if two bitmapdatas were identical. (Just checking if 0 was returned.)

Assuming there are some practical use cases for the actual difference comparison, I’m actually curious to how you would have it return. I also think this design seems pretty screwy, I just don’t know how I would make it better.

 
Flag Post

You make it throw exceptions instead of returning int values.

If I needed a function to tell me if the width and height of two bitmaps weren’t the same I would write it myself.

 
Flag Post

Yea, and what’s the practical use of that? Obviously you can argue that any function has one practical application which is to return its output when called. You might even think it’s a clever retort but it’s just a tautology.

That was not tautology nor a retort, it was a reminder. Look at Drakim’s answer above me.

If I needed a function to tell me if the width and height of two bitmaps weren’t the same I would write it myself.

Hell, you SHOULD, since compare makes another bitmapdata, making it heavyweight.

But the compare function does not simply check the width and height of two bitmaps, it compares every single pixel to every single pixel of the other. So if you have two 2600 * 2600 bitmaps, that’s 27,040,000 operations.

Even if you remove my answer above (that this most likely is being called by other functions), this should be built in Flash. Being a native function, this makes it run faster, and when you have that much operations happening, it should ran fast.

The reason I reminded you that is because I thought you would have discerned my intentions, but apparently, you haven’t. Let’s see how deep the rabbit hole goes:

If I simply wanted to check if two images are the same, it would be useful, since it’s so f*cking fast being a native function.

If I wanted to right an iterative tracing algorithm that traces an image, the data it throws back to me is IMMENSELY useful, coupled with creative uses of histogram.

If I wanted to check if two bitmaps are ‘close enough’, again it would be useful, since I can check the difference in the data it throws back to me and if it’s above a certain percentage, I can make it run.

So on and so forth.

EDIT: I thought I would benchmark it, but found out somebody already did

You make it throw exceptions instead of returning int values.

No. See below.

*: And do you really want to get into how horrible it is to have a function that can return values of type int or BitmapData depending on what its input was? That’s terrible, horrible coding practice. If someone posted a thread in here with a function that does that people would ignore their actual question and rip them a new one for it, with good reason.

Apparently, the thousands of programming language designers both past and present are no match to the collective prowess of kongregate programmers.

There are LOTS, and I mean a LOTS of functions in different programming languages that do this, not just in AS3.

I’m not trying to start a fight, I am simply pointing out things :P

 
Flag Post

Your post is dripping with condescension and a large part of it is not right, not wrong, but outright nonsense, yet in the interest of staying on topic I’ll just say this:

1) Checking if bitmapDatas are the same size is not a valid use of compare() because if they happen to be the same size compare will then perform useless pixel-by-pixel operations on the entire bitmapdata. This:

if (bmd1.width == bmd2.width && bmd1.height == bmd2.height) goHogWild();

is a much better use of CPU time.

2) compare() is not “an iterative tracing algorithm that traces an image”. If you really want to make that claim you need to support it with something more tangible than bold formatting, the use of the Caps Lock key, and a lot of hand waiving.

3) compare() cannot check if two pixels are “close enough” in color because it will return 0xAA000000 in every case where the RGB components of pixel2 are the same or higher than those of pixel1 (where AA is the alpha channel value of pixel1), even if pixel1 is pure black and pixel2 is pure white. Exception: if the RGB values of both pixels are exactly the same it will return pure white for the RGB.

The only thing you are pointing out is that you have very little idea of what compare() does and absolutely no clue what it could be used for. And that’s fine, I have no clue what it could be used for either. The closest I can get to is ‘some sort of screwy difference filter, under some very specific assumptions’. You could just admit that you were wrong and move on.

 
Flag Post

Eh, most programming languages wouldn’t even be able to do this strange multitype return. But even the ones that can, it’s pretty much considered bad practice in all circumstances, in all situations.

The “proper” way of doing it would be to have it throw an exception if the widths\heights do not match, or if the object you supplied was not a bitmapdata, and so on. That way, you can wrap a catch around it to capture that error.

When you return different types, it breaks the typing. What should you treat the return value as, Int? BitmapData?

For this rarely used function it doesn’t seem like a big deal, but imagine if Adobe did this on all it’s native functions. Every time you called a native function you would have to spend a few lines on receiving the return value and making sure that you have the correct type. It would increase the complexity of your code and eat up a lot of performance.

And for what exactly, so that your function that tells you if two bitmapdatas have similar pixmap colors, can also tell you if the two bitmapdatas has different widths? There is no good design in mashing together functionality like that.

There simply is no good reason to do this.

 
Flag Post

Your post is dripping with condescension and a large part of it is not right, not wrong, but outright nonsense, yet in the interest of staying on topic I’ll just say this:

You say that when you seemed to ignore my whole post!

1) Checking if bitmapDatas are the same size is not a valid use of compare() because if they happen to be the same size compare will then perform useless pixel-by-pixel operations on the entire bitmapdata. This:

I challenge you to quote me on that, when I even argued against it!

If I needed a function to tell me if the width and height of two bitmaps weren’t the same I would write it myself.

Hell, you SHOULD, since compare makes another bitmapdata, making it heavyweight.

When you only need to check size, write a function, because compare is heavyweight because of the bitmapdata!

1 is outright nonsense.

2) compare() is not “an iterative tracing algorithm that traces an image”. If you really want to make that claim you need to support it with something more tangible than bold formatting, the use of the Caps Lock key, and a lot of hand waiving.

Again, I challenge you to quote me on this. I never said it is “an iterative tracing algorithm that traces an image”, I said I would use it for it!

3) compare() cannot check if two pixels are “close enough” in color because it will return 0xAA000000 in every case where the RGB components of pixel2 are the same or higher than those of pixel1 (where AA is the alpha channel value of pixel1), even if pixel1 is pure black and pixel2 is pure white. Exception: if the RGB values of both pixels are exactly the same it will return pure white for the RGB.

cough

The only thing you are pointing out is that you have very little idea of what compare() does and absolutely no clue what it could be used for. And that’s fine, I have no clue what it could be used for either. The closest I can get to is ‘some sort of screwy difference filter, under some very specific assumptions’. You could just admit that you were wrong and move on

I think it is you who have absolutely no clue for it’s use. I give you examples and you cannot even find creative uses for the data it throws back to you.

Eh, most programming languages wouldn’t even be able to do this strange multitype return. But even the ones that can, it’s pretty much considered bad practice in all circumstances, in all situations.

True, not all programming languages can, and I do believe you have some valid points. But I do not believe it is bad practice in “all circumstances, in all situations”. One good example where this could be good is – this (sorts of) function! Almost all of compare and difference methods in multiple programming languages returns 0 when it is equal but returns the “difference” when not.

There is one way the method can have been better though, accepting a boolean if you need the bitmap data, this would make it even faster (Check my link on my previous post).

EDIT: Wait a minute, I forgot you also ‘ignored’ the ‘very little idea’ of what I could use compare for – The obvious comparing bitmaps if they are equal!

 
Flag Post

The thing is though, even if you need to check if two bitmapdatas are equal, this function is a pretty bad fit, since if they aren’t equal in pixel values, then an entirely new bitmapdata gets allocated in memory, just to be thrown to the GC afterwards.

 
Flag Post
Originally posted by Drakim:

The thing is though, even if you need to check if two bitmapdatas are equal, this function is a pretty bad fit, since if they aren’t equal in pixel values, then an entirely new bitmapdata gets allocated in memory, just to be thrown to the GC afterwards.

Yes, and I actually agree to you on this, as I said it should accept a boolean if you wanted the bitmap data.

You might find this interesting though:
Here

To quote:

Yeah, BitmapData.compare() is pretty good. It showed a dramatic slowdown when given completely different images but I am fairly sure that was due to the time taken to generate a new huge BitmapData object. It would be nice for BitmapData.compare() to take a parameter that told it not to bother making the BitmapData showing where the differences lie, and instead just return its number codes.

Choosing which areas of the image to compare first is nice smart thinking, but given that BitmapData.compare() can examine a million pixels in a handful of milliseconds it is unlikely to be a necessary optimisation (see also: root of all evil). Especially as I assume this process would only be performed once when the animations are first loaded, or at least wouldn’t need to be repeated each frame.

 
Flag Post

It would be even better to separate the functionality into separate functions.

You could have one function .comparePixels that takes two bitmapdatas, and returns a bitmapdata with the difference in pixel values. If widths and heights is not equal, it could throw an exception, or return null.

Then you could have one function .identicalPixels that takes two bitmapdatas, and returns a bool, true for identical, false for non-identical.

That way, you get type safety, performance, and no confusion. Overall I think this function is so messy that it would have been best if Adobe kept it private. All I can see it doing is cause a lot of grief and problems, for very little gain.

 
Flag Post

Very strong points and I do agree, except for the last paragraph. There is a lot of gain you can get in it, since the two functions you mentioned aren’t present :3 Making it private would cause a lot more grief and problems, this time, for no gain.

But if the two functions are there, then right on.

I still find compare good though, it packs significant portability and it mirrors the API of many languages. It also reminds me of diff.

 
Flag Post

So, you agree that compare() is not useful for checking size congruence. You agree that compare() is not “an iterative tracing algorithm that traces an image” (whatever that is). So much for two candidates of practical applications, even you won’t support them. And did you look at the link?

Some simple math. If you circumscribe a circle with a square so that it is tangent to that circle in four points, and the circle has radius R, the surface area of the circle is pi R^2 and the surface area of the square is (2R)^2 = 4 R^2. The ratio of the surface area of the circle to the square is therefore pi/4, or about 78.5%

The link you provided found that the two bitmaps, including whitespace, have a “difference percentage” of about 76%, which leads to the possible conclusions that:
1) the circle is not exactly circumscribed by the boundaries of the bitmapData, but there’s sliver of extra padding on the edges.
2) all the algorithm did in practice was count the white pixels in the original images.

Also note that the use of compare() does not give the answer, the real number crunching is done through getPixel(), an actually useful function. The only thing compare() did was remove half the calls to getPixel() by generating a screwy subtraction filtered bitmapData first.

I like how the algorithm checks for black pixels as a criterion for color equality when, at least according to the documentation, pixels that were the same color on both bitmapData should have been turned white. It makes me think that the final answer is only coincidentally close to a value that would make sense. Without seeing what the actual output from compare() looks like it’s pretty hard to get an idea. And note how the poster did not provide the output bitmapData. I would use the jpg image that was posted to try and reconstitute the original bitmapDatas, but compare() is so fickle anyway there is no guarantee I’d get anything close enough to the original images that compare() would then give a comparable answer.

And that’s the crux of the problem really: compare() gives output that varies wildly depending on very minor differences in the input. I have posted examples of that already.

Now if your point was that you could use compare() to make it output a garbage bitmapData that you can then use to generate a garbage number, yes, you can. But Math.random() is faster.

 
Flag Post

ROFL, you ignored me again:

Wait a minute, I forgot you also ‘ignored’ the ‘very little idea’ of what I could use compare for – The obvious comparing bitmaps if they are equal!

Did you see the benchmarks?

So, you agree that compare() is not useful for checking size congruence. You agree that compare() is not “an iterative tracing algorithm that traces an image”

And getPixel() does not magically compare the images. You use the data it throws back to you. Same as with compare for the algorithm. You say I agree that compare() is not “an iterative tracing algorithm that traces an image”, when I never even said it was. I said it can be used for such, it is not a straight, out of the box solution for an algorithm.

(whatever that is)

As I said, if you can’t find a way to use it, don’t expect every single person in the world not to.

Some simple math. If you circumscribe a circle with a square so that it is tangent to that circle in four points, and the circle has radius R, the surface area of the circle is pi R^2 and the surface area of the square is (2R)^2 = 4 R^2. The ratio of the surface area of the circle to the square is therefore pi/4, or about 78.5%

Are you familiar with the word, specialized? And are you also familiar with the word, colors?

Now if your point was that you could use compare() to make it output a garbage bitmapData that you can then use to generate a garbage number, yes, you can. But Math.random() is faster.

I am literally left baffled as to which parts of my posts elicited such a response.

 
Flag Post
Originally posted by Secretmapper:

Very strong points and I do agree, except for the last paragraph. There is a lot of gain you can get in it, since the two functions you mentioned aren’t present :3

The problem is that even if Adobe were to add these two functions, it would still have to keep this .compare() function because removing it would break any .swf files that relies on it. One has to be incredibly careful about API changes due to backwards compatibility. In essence, once you have added some bloat, you can never ever remove it.

That is why Adobe should never have made this function public. They should have kept it private, and let developers write their own comparison code, and if they one day find that it is a bottleneck, add the more sensible versions instead.