In my application I read RGB pixel values from several images using fast unmanaged code and then convert them to HSB colors. Now I'd like to build an HSB histogram using the following partitions:
- Hue: 18 partitions, resulting in intervals of 20 from 0...360
- Saturation: 3 partitions, resulting in intervals of 0,33 from 0...1
- Brightness: 3 partitions, resulting in intervals of 0,33 from 0...1
So my histogram has a total of 18*3*3=162 partitions (bins) which consist of the lower interval borders for each channel:
- Bin1: [0, 0, 0]
- Bin2: [0, 0, 0.33]
- Bin3: [0, 0, 0.66]
- Bin4: [0, 0.33, 0]
- Bin5: [0, 0.33, 0.33]
- ...
- Bin162: [340, 0.66, 0.66]
I implemented this pretending that each bin would be an HSB color itself. So I calculated the bin interval borders, created HsbColor instances from those values and put the colors (wrapped in the HsbHistogramBin class) in a simple list. When adding a new HsbColor to my histogram, I use the following code to determine which bin I need to increment:
private HsbHistogramBin FindBin(HsbColor color)
{
HsbHistogramBin bin = null;
bool foundBin = false;
for (int i = Bins.Count - 1; i >= 0; i--)
{
bin = Bins[i];
if (bin.Color.Hue > color.Hue)
continue;
if (bin.Color.Saturation > color.Saturation)
continue;
if (bin.Color.Brightness > color.Brightness)
continue;
foundBin = true;
break;
}
return foundBin ? bin : null;
}
public void AddColor(HsbColor color)
{
FindBin(color).Value++;
}
Obviously this is way too slow. In a worst-case scenario, each pixel needs 162 iterations to find its bin which results in at least millions of iterations for one single image.
My question is: How can I speed this data structure up so that I can immediately find the right bin for my pixels? A simple array with the length of 162 might work but how do I calculate the right bin index for a given pixel that isn't yet reduced to the mentioned partitions and might contain values like [259.234, 0.5634, 0.90534]?
You can convert your HSV number into one unsigned long like so:
This is your bin index.
Why not just simply use a 3 dimensional array? Like so:
NB: I'm assuming here that your total pixel count (more precisely, the maximum number of pixels that will fall into 1 bin) will not exceed
int.MaxValue
. Otherwise, consider usinglong
datatype for the histogram instead ofint
.