2016-11-04 3 views
1

Я пытаюсь реализовать функцию гауссовского размытия изображения nxn с гауссовым ядром определенного радиуса rs = ((int) 2.75 * sigma + 0.5).«Разрыв» гауссовского размытия вокруг краев изображения

for (x=0;x<n;x++){ 
    for (y=0;y<n;y++){ 

     sum=0.0,wsum=0.0; 

     //Position correction at the edges 

     if(x-rs<0){ 
      ix=0; 
     } 
     else ix=rs; 

     if(y-rs<0){ 
      iy=0; 
     } 
     else iy=rs; 

     if (x+rs>n-1){ 
      jx=n-1-x; 
     } 
     else jx=rs; 

     if (y+rs>n-1){ 
      jy=n-1-y; 
     } 
     else jy=rs; 
     //Kernel mean value correction at the edges 

     if (x-rs < 0){ 
      meanx=x+((int)rs/2); 
     } 
     else meanx=x; 

     if(y-rs<0){ 
      meany=y+((int)rs/2); 
     } 
     else meany=y; 

     if (x+rs>n-1){ 
      meanx=x-((int)rs/2); 
     } 
     else meanx=x; 

     if (y+rs>n-1){ 
      meany=y-((int)rs/2); 
     } 
     else meany=y; 


     for (i=x-ix;i<=x+jx;i++){ 
      for (j=y-iy;j<=y+jy;j++){ 

       weight=1/(2*M_PI*sigma*sigma)*exp(-((meanx-i)*(meanx-i)+(meany-j)*(meany-j))/(2*sigma*sigma)); 
       sum+=pic1.intenzity[i][j]*weight; 
       wsum+=weight; 
      } 
     } 

     pic2->intenzity[x][y]=((int)sum/wsum+0.5); 

     fprintf(fw,"%d\n",pic2->intenzity[x][y]); 
    } 

Когда я не использую коррекции среднего значения по краям результат выглядит следующим образом:

without mean value correction

и когда я попытался смещая среднее значение ядра создает разрыв также на нижнем и правом краю изображения:

with shifting the mean value to rs/2

я должен был сделать этот край позиционированием n, потому что сумма будет переполняться. Теперь кажется, что гауссова свертка внезапно прыгает по какой-то причине, когда она находится в положении rs от верхнего и левого краев как для x, так и для y. Я бы хотел, чтобы он вел себя так же, как в «интерьере» изображения, или, возможно, заставлял интенсивности исчезать до 0, когда позиция приближается к краю.

Я мог бы увеличить изображение с помощью rs, но это вызовет проблемы с положением края.

Спасибо за любую помощь :) проницательную

+0

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

+0

Я попытался сохранить sum/wghtsum в отдельную матрицу float, а затем снова записать ее в пиксели в int, но сделал то же самое. – Martin

+0

Я имел в виду кастинг на 'int', который вы делаете почти на каждом шагу. Убедитесь, что все ваши переменные типа double, и удалите каждый экземпляр '(int)', это усекает десятичное число, когда оно может содержать важные данные, особенно потому, что вы выполняете несколько вычислений. Вы можете быть в значительной степени. –

ответ

0

Давайте посмотрим на типичный ядра фильтра применяется к изображению, в псевдокоде. Позволяет использовать переменные

# source[y][x] Old image (read-only) 
# target[y][x] New image (write-only) 
# image_height Image height (y = 0 .. image_height-1) 
# image_width  Image width (x = 0 .. image_width-1) 
# filter[y][x] Filter (weights) to be applied 
# filter_height Filter height (y = 0 .. filter_height-1) 
# filter_width Filter width (x = 0 .. filter_width-1) 
# filter_y  Target pixel y coordinate in filter (filter_height/2) 
# filter_x  Target pixel x coordinate in filter (filter_width/2) 

, где filter_y = floor(filter_width/2) и filter_x = floor(filter_height/2), если фильтр с центром на целевом пикселе (т.е.. Симметричным). Псевдокод затем примерно

For base_y = 0 to image_height - 1: 

    # y range relative to base_y ... 
    min_y = -filter_y 
    max_y = filter_height - 1 - filter_y 

    # ... must not exceed the image boundaries. 
    If min_y + base_y < 0: 
     min_y = -base_y 
    End If 

    If max_y + base_y < 0: 
     max_y = -base_y 
    End If 

    If min_y + base_y >= image_height: 
     min_y = image_height - 1 - base_y 
    End If 

    If max_y + base_y >= image_height: 
     max_y = image_height - 1 - base_y 
    End If 

    For base_x = 0 to image_width - 1: 

     # x range relative to base_x ... 
     min_x = -filter_x 
     max_x = filter_width - 1 - filter_x 

     # ... must not exceed the image boundaries. 
     If min_x + base_x < 0: 
      min_x = -base_x 
     End If 

     If max_x + base_x < 0: 
      max_x = -base_x 
     End If 

     If min_x + base_x >= image_width: 
      min_x = image_width - 1 - base_x 
     End If 

     If max_x + base_x >= image_height: 
      max_x = image_width - 1 - base_x 
     End If 

     ValueSum = 0 
     WeightSum = 0 

     For y = min_y to max_y: 
      For x = min_x to max_x: 
       Value = source[y + base_y][x + base_x] 
       Weight = filter[y + filter_y][x + filter_x] 
       ValueSum = ValueSum + Value * Weight 
       WeightSum = WeightSum + Weight 
      End For 
     End For 

     If WeightSum != 0: 
      target[base_y][base_x] = ValueSum/WeightSum 
     End If 

    End For 
End For 

Внутри самого внутреннего цикла, [base_y][base_x] относится к целевому пикселю, тот, который мы вычислительном; и [y+base_y][x+base_x] относится к исходному пикселю, взвешенному по [y+filter_y][x+filter_x]. x и y - относительные значения от -filter_x и -filter_y до filter_width-1-filter_x и filter_height-1-filter_y, соответственно.

До тех пор, пока ValueSum и WeightSum имеют достаточный диапазон, тот же код работает, если данные изображения и фильтра являются целыми или с плавающей запятой.

Хитрая часть, а часть вызывает артефакты ОП видит, как вычислить min_y, max_y, min_x и max_x правильно.

Для отладки удалите две сокровенные петли, и вместо того, чтобы напечатать что-то вроде

printf("y = %d, ymin = %d (%d), ymax = %d (%d)\n", 
     base_y, min_y, min_y + base_y, max_y, max_y + base_y); 

внутри внешнего контура (нет необходимости печатать для каждого base_x!), И

printf("x = %d, xmin = %d (%d), xmax = %d (%d)\n", 
     base_x, min_x, min_x + base_x, max_x, max_x + base_x); 

раз в самом внутреннем цикле (нет необходимости печатать его снова для каждого base_y), например if (y == 0) printf("...");. Это выводит линии image_width + image_height и позволяет проверить правильность диапазонов.

В случае с ОП диапазоны неправильны вблизи краев изображения; то есть некоторые из их статей if, соответствующих вышеуказанному псевдокоду, вычисляют/присваивают неверные значения min_x, max_x, min_y и max_y.

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