2014-12-20 3 views
2

У меня есть цикл, который слишком медленный в C#. Я хочу знать, есть ли более быстрый способ обработки через эти массивы. В настоящее время я работаю в .NET 2.0. Я не против обновления этого проекта. Это часть теоретической концепции обработки изображений, включающей уровни серого.Как это сделать быстрее всего? Массивы изображений

  • количество пикселей (PixCnt = 21144402)
  • g_len = 4625
  • list1d - 1Dimensional массив изображения с верхней гранью указанного выше количества пикселей.
  • pg - держатель интенсивности уровня серого.

Эта функция создает индекс этих значений. следовательно, pgidx.

int[] pgidx = new int[PixCnt]; 
sw = new Stopwatch(); 
sw.Start(); 
for (i = 0; i < PixCnt; i++) 
{ 
    j = 0; 
    pgidx[i] = 0; 
    while (list_1d[i] != pg[j] && j < g_len) j++; 
    if (list_id[i] == pg[j]) 
     pgidx[i] = j 
} 
sw.stop(); 
Debug.WriteLine("PixCnt Loop took" + sw.ElapsedMilliseconds + " ms"); 
+2

Сколько времени стоит слишком долго? – hatchet

+0

От 5 до 10 минут. –

+0

Ваше имя переменной трудно понять. –

ответ

1

Я думаю, используя словарь, чтобы сохранить то, что находится в pg массиве ускорить его. g_len - это 4625 элементов, поэтому вы, вероятно, будете в среднем около 2312 итераций внутреннего цикла. Замена этого с помощью одного хэширования в словаре должна быть быстрее. Поскольку внешний цикл выполняет 21 миллион раз, ускорение тела этого цикла должно получить большие награды. Я предполагаю, что приведенный ниже код ускорит ваше время на 100 - 1000 раз быстрее.

var pgDict = new Dictionary<int,int>(g_len); 
for (int i = 0; i < g_len; i++) pgDict.Add(pg[i], i); 
int[] pgidx = new int[PixCnt]; 
int value = 0; 
for (int i = 0; i < PixCnt; i++) { 
    if (pgDict.TryGetValue(list_id[i], out value)) pgidx[i] = value; 
} 

Обратите внимание, что установка pgidx[i] к нулю, если совпадение не найдено, не является необходимым, так как все элементы массива уже инициализируется нулем при создании массива.

Если существует вероятность того, что значение в pg появится более одного раза, сначала нужно проверить, был ли этот ключ уже добавлен, и пропустить добавление его в словарь, если он есть. Это подражало бы вашему текущему поведению поиска первого матча. Для этого замените строку, в которой словарь построен с этим:

for (int i = 0; i < g_len; i++) if (!pgDict.ContainsKey(pg[i])) pgDict.Add(pg[i], i); 
+0

Ваша концепция кажется блестящей, но: я получаю «pgDict.Add (pg [i], i)» - элемент с тем же ключом уже добавлен. Значения уровня серого не являются дублирующими. –

+0

@RobertKoernke - Я думал, что это возможно, и упомянул об этом в моем последнем абзаце. Теперь, когда вы сказали, что это действительно так, я отредактировал свой ответ, чтобы показать код, который будет иметь дело с этим. – hatchet

+0

До 551 мс приятно! –

0

Если диапазон значений пикселей в pq позволяет это (скажем 16 BPP = 65536 записей), вы можете создать вспомогательный массив, который отображает все возможные уровни серого до значения индекса в pg. Заполнение этого массива выполняется за один проход за pg (после инициализации всех нулей).

Затем конвертировать list_1d в pgidx с прямым просмотром таблицы.

Если таблица слишком большая (больше, чем изображение), то сделайте так, как @hatchet ответил.

Смежные вопросы