1

Basically, I want to get the most common ARGB value that appears in a BitmapData. That is, I want to know which exact pixel colour is the most abundant in the image. I tried going through every pixel of the image and counting whenever a colour that already exists comes up, but that's way too slow, even with relatively small images. Does anybody know a faster method for this, maybe using the BitmapData.histogram() function or something?

Ideally the process should be near instantaneous for images around at least 1000x1000 pixels.

puggsoy
  • 1,270
  • 1
  • 11
  • 34
  • 1
    I found a similar question with a good answer, it might help you http://stackoverflow.com/a/9879812/1123633 – Johan Lindkvist Jan 17 '13 at 21:50
  • I've seen that: unfortunately the solution appears to find the average colour, which is not what I'm looking for. I'm looking for the single colour value that appears the most times in an image. Like if you have 20 pixels that are `0xFF89ae00`, and 10 that are `0xFFae0089`, the resultant colour I would get would be `0xFF89ae00`, because that's the colour that most pixels have. – puggsoy Jan 17 '13 at 22:18
  • Oh okay i misunderstood the answer (to the one i linked), sorry ^^. – Johan Lindkvist Jan 17 '13 at 22:43
  • Are you using [getPixel()](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#getPixel()) or [getVector()](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#getVector())? – NoobsArePeople2 Jan 17 '13 at 23:26
  • I was using `getPixel32()`: now I see that `getVector()` is better for this use, but I hadn't used it before Vesper's answer. – puggsoy Jan 18 '13 at 09:01
  • I think that this could be usefull for you: http://blog.soulwire.co.uk/code/actionscript-3/extract-average-colours-from-bitmapdata – fenixkim Jan 18 '13 at 13:39
  • Sorry, that's the same as Johan's suggestion: it gives the average, not the most common. – puggsoy Jan 18 '13 at 14:13

2 Answers2

1

Run through bitmapData.getVector() with a Dictionary to hold numbers, then sort that Dictionary's key-value pairs by value and get the key of maximum.

var v:Vector.<uint>=yourBitmapData.getVector(yourBitmapData.rect);
var d:Dictionary=new Dictionary();
for (var i:int=v.length-1; i>=0;i--) {
    if (d[v[i]]) d[v[i]]++; else d[v[i]]=1;
}
var maxkey:String=v[0].toString();
var maxval:int=0;
for (var k:String in d) {
    if (d[k]>maxval) {
        maxval=d[k];
        maxkey=k;
    }
}
return parseInt(maxkey); // or just maxkey
Vesper
  • 18,599
  • 6
  • 39
  • 61
  • Thanks, that works greatly (I'm not sure why you're iterating through the `Vector` backwards though, works fine for me forwards). Unfortunately it's still slower than I need it to be (although it is comparatively fast). I'll leave this unanswered to see if someone knows of something quicker, if that's even possible. If there aren't any answers for the next day or two I'll accept this one. – puggsoy Jan 18 '13 at 08:52
  • 1
    I expect nothing is faster, as you need to query every single pixel and make an exact color histogram, this requires complete iteration. Why backwards - we don't need to maintain order to count, but if we go forwards, we constantly check vector length, it isn't as fast as checking against zero. – Vesper Jan 18 '13 at 10:21
  • Ah, good point, never thought of that. I'll be sure to remember that in the future for when order doesn't matter. Most likely you're right, this is probably the fastest method with this level of accuracy, but may as well see if something magical comes up. – puggsoy Jan 18 '13 at 11:08
  • 1
    @puggsoy It's just as easy to save the length in a local variable. I do this very often: `var lng:uint = myArray.length; for(var i:uint = 0; i < lng; i++) {... }` – Joshua Honig Jan 18 '13 at 19:23
0

I haven't worked with shaders at all, but I think you might be able to get faster results. Looping through pixels is faster at the shader level.

I'd try by creating essentially the same loop in the shader, and paint the entire resulting bitmap with the most used colour and sample that (unless you can get a variable directly out of the shader)

this should be significantly faster

Daniel
  • 34,125
  • 17
  • 102
  • 150