C #: поиск быстрой структуры данных для добавления пикселей в секционированную гистограмму HSB - PullRequest
2 голосов
/ 18 апреля 2011

В моем приложении я считываю значения пикселей RGB из нескольких изображений, используя быстрый неуправляемый код, а затем преобразую их в цвета HSB. Теперь я хотел бы построить гистограмму HSB, используя следующие разделы:

  • Оттенок: 18 разделов, в результате интервалы от 20 до 0 ... 360
  • Насыщенность: 3 раздела, в результате интервалы 0,33 от 0 ... 1
  • Яркость: 3 раздела, в результате интервалы 0,33 от 0 ... 1

Таким образом, моя гистограмма имеет в общей сложности 18 * 3 * 3 = 162 разбиения (ячейки), которые состоят из нижних границ интервалов для каждого канала:

  • Бин1: [0, 0, 0]
  • Bin2: [0, 0, 0,33]
  • Бин3: [0, 0, 0,66]
  • Бин4: [0, 0,33, 0]
  • Бин5: [0, 0,33, 0,33]
  • ...
  • Bin162: [340, 0,66, 0,66]

Я реализовал это, делая вид, что каждый бин будет самого цвета HSB. Поэтому я вычислил границы интервала бина, создал экземпляры HsbColor из этих значений и поместил цвета (обернутые в класс HsbHistogramBin) в простой список. При добавлении нового HsbColor в мою гистограмму я использую следующий код, чтобы определить, какой бин мне нужно увеличить:

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++;
}

Очевидно, это слишком медленно. В худшем случае каждому пикселю требуется 162 итерации, чтобы найти свою ячейку, что приводит к по меньшей мере миллионам итераций для одного изображения.

У меня такой вопрос: как я могу ускорить эту структуру данных, чтобы я мог сразу же найти нужную ячейку для своих пикселей? Простой массив длиной 162 может работать, но как рассчитать индекс правильного бина для заданного пикселя, который еще не сокращен до упомянутых разделов и может содержать значения, такие как [259.234, 0.5634, 0.90534]?

Ответы [ 2 ]

2 голосов
/ 18 апреля 2011

Почему бы просто не использовать трехмерный массив?Вот так:

int[,,] histogram = new int[18, 3, 3];

// initialize to 0
for(int h = 0; h < 18; h++) {
  for(int s = 0; s < 3; s++) {
    for(int b = 0; b < 3; b++) {
      histogram[h, s, b] = 0;
    }
  }
}

// foreach pixel...
HsbColor c = ... // color of pixel
int h = (int)(c.Hue / 20);
int s = (int)(c.Saturation * 3);
int b = (int)(c.Brighthess * 3);

// take care of boundary cases (Hue, Saturation or Brightness maxed out)
if(h >= 18) h = 17;
if(s >= 3) s = 2;
if(b >= 3) b = 2;

histogram[h, s, b]++;

Примечание: здесь я предполагаю, что общее количество пикселей (точнее, максимальное количество пикселей, попадающих в 1 ячейку) не будет превышать int.MaxValue.В противном случае рассмотрите возможность использования long типа данных для гистограммы вместо int.

0 голосов
/ 18 апреля 2011

Вы можете преобразовать свой номер HSV в одну длинную без знака следующим образом:

ulong colorLookupValue = (color.Hue/18) * 9 + (ulong)((color.Saturation*3) * 3) + (ulong)(color.Brightness * 3) 

Это ваш индекс корзины.

...