Цикл развертывания многомерного массива

Недавно я пытался развернуть внутренние циклы i и j в этом многомерном массиве, но filter->get(i,j) всегда портит текстуру изображения. Может ли кто-нибудь помочь мне развернуть цикл i и j? Спасибо.

Моя попытка:

double
applyFilter(struct Filter *filter, cs1300bmp *input, cs1300bmp *output)
{

     long long cycStart, cycStop;

     cycStart = rdtscll();

    output -> width = input -> width;
    output -> height = input -> height;
int a = filter -> getDivisor();
int n = filter -> getSize();
for (int plane = 0; plane < 3; plane++){
    for(int row = 1; row < (input -> height) - 1 ; row = row + 1) {
        for(int col = 1; col < (input -> width) - 1; col = col + 1) {
            int value = 0;
            int val1, val2;
            for (int j = 0; j < n; j++) {
                for (int i = 0; i < n; i+=2) {
                    val1 = val1 + input -> color[plane][row + i - 1][col + j - 1]
                    * filter -> get(i, j);
                    val2 = val2 + input -> color[plane][row + i][col + j -1] * filter->get(i+1,j);
                }
            }
            value = (val1 + val2) / a;
            if ( value  < 0 ) { value = 0; }
            if ( value  > 255 ) { value = 255; }
            output -> color[plane][row][col] = value;
        }

    }
}

 cycStop = rdtscll();
 double diff = cycStop - cycStart;
 double diffPerPixel = diff / (output -> width * output -> height);
 fprintf(stderr, "Took %f cycles to process, or %f cycles per pixel\n",
  diff, diff / (output -> width * output -> height));

 return diffPerPixel;
}

Оригинал:

int a = filter -> getDivisor();
int n = filter -> getSize();    
for (int plane = 0; plane < 3; plane++){
    for(int row = 1; row < (input -> height) - 1 ; row = row + 1) {
        for(int col = 1; col < (input -> width) - 1; col = col + 1) {
            int value = 0;
            for (int j = 0; j < n; j++) {
                for (int i = 0; i < n; i++) {
                    value = value + input -> color[plane][row + i - 1][col + j - 1]
                    * filter -> get(i, j);
                }
            }
            value = value / a;
            if ( value  < 0 ) { value = 0; }
            if ( value  > 255 ) { value = 255; }
            output -> color[plane][row][col] = value;

person user2998285    schedule 16.11.2013    source источник


Ответы (2)


Попробуйте заменить внутренний цикл на:

int value = 0;
int val1 = 0, val2 = 0;
for (int j = 0; j < n; j++) { 
    int i;
    for (i = 0; i < n; i+=2) {
        val1 += input->color[plane][row+i-1][col+j-1] * filter->get(i,j);
        val2 += input->color[plane][row+i  ][col+j-1] * filter->get(i+1,j);
    } 
    if (i < n)
        val1 += input->color[plane][row+i-1][col+j-1] * filter->get(i,j);
} 
value = (val1 + val2) / a;
person jaeheung    schedule 16.11.2013

Ваш метод верен только в том случае, если n кратно 2. В противном случае вы пропустите одну строку.

ДОБАВЛЕН:

Прежде всего, я только что понял, что вы забыли инициализировать val1 и val2, что, вероятно, является основной причиной ваших проблем.

Во-вторых, мне кажется, что ваш код был написан специально для размеров фильтра 3:

  • Для меньших фильтров вы вообще не получаете доступ к границам.
  • Для больших вы получаете доступ к позициям за пределами изображения, например. [row + i - 1] становится больше или равно input->height.

Если вы хотите использовать только фильтры размера 3, я бы просто полностью развернул внутренние циклы. В противном случае проверьте границы значений строки и столбца.

Теперь, чтобы развернуть цикл, я бы порекомендовал выполнить поиск в Google, так как вы можете найти много примеров того, как это сделать правильно. Его можно найти на странице Википедии.

В вашем случае самым простым решением будет:

int value = 0;
int val1=0, val2=0;
for (int j = 0; j < n; j++) {
    for (int i = 0; i < n-1; i+=2) {
        val1 = val1 + input->color[plane][row+i-1][col+j-1] * filter->get(i  ,j);
        val2 = val2 + input->color[plane][row+i  ][col+j-1] * filter->get(i+1,j);
    }
    if (n%2 !=0) {
        val1 = val1 + input->color[plane][row+n-2][col+j-1] * filter->get(n-1,j);
    }
}
value = (val1 + val2) / a;

Если вы хотите развернуть цикл еще больше, более общий способ будет (например, для 4):

int value = 0;
int val1=0, val2=0, val3=0, val4=0;
for (int j = 0; j < n; j++) {

    for (int i = 0; i < n-3; i+=4) {
        val1 = val1 + input->color[plane][row+i-1][col+j-1] * filter->get(i  ,j);
        val2 = val2 + input->color[plane][row+i  ][col+j-1] * filter->get(i+1,j);
        val3 = val3 + input->color[plane][row+i+1][col+j-1] * filter->get(i+2,j);
        val4 = val4 + input->color[plane][row+i+2][col+j-1] * filter->get(i+3,j);
    }
    switch (n % 4) {
        case 3: val1+=input->color[plane][row+n-4][col+j-1] * filter->get(i+n-3,j);
        case 2: val1+=input->color[plane][row+n-3][col+j-1] * filter->get(i+n-2,j);
        case 1: val1+=input->color[plane][row+n-2][col+j-1] * filter->get(i+n-1,j);
    }
    value = (val1 + val2 + val3 + val4) / a;
}

ПРИМЕЧАНИЕ.
Имейте в виду, что в зависимости от размера вашего фильтра, используемого компилятора и параметров компилятора, а также от вашей системы приведенные выше решения могут не ускорить ваш код, а даже замедлить его. Вы также должны знать, что компилятор обычно может выполнить развертывание цикла за вас (например, с помощью -funroll-loops в gcc), если это имеет смысл.

person MikeMB    schedule 16.11.2013
comment
Итак, я могу сделать что-то вроде: for (;i ‹n; i++){ val3 = val3 + input -> color[plane][row+i-1][col+j-1] * filter-›get(i, j)} В основном компенсирует все остальное. - person user2998285; 16.11.2013
comment
Я изменил свой ответ, чтобы дать вам более полный ответ на ваш вопрос. Надеюсь, я не ошибся с индексами. - person MikeMB; 16.11.2013