2016-09-25 2 views
1

Мне нужно реализовать Gaussian Blur в Java для матриц 3x3, 5x5 и 7x7. Вы можете исправить меня, если я ошибаюсь:Java: реализация Gaussian Blur

  1. Я матрица (M) 3х3 (среднее значение M (0, 0)):

    1 2 1 
    2 4 2 
    1 2 1 
    
  2. Я беру один пиксель (Р) от изображения и для каждого пикселя ближайшего:

    s = M(-1, -1) * P(-1, -1) + M(-1, 0) * P(-1, 0) + ... + M(1, 1) * P(1, 1) 
    
  3. , то разделение его общая стоимость матрицы:

    P'(i, j) = s/M(-1, -1) + M(-1, 0) + ... + M(1, 1) 
    

Это все, что делает моя программа. Я оставляю крайние пиксели не меняющимися.

Моя программа:

for(int i = 1; i < height - 1; i++){ 
    for(int j = 1; j < width - 1; j++){ 
     int sum = 0, l = 0; 
     for(int m = -1; m <= 1; m++){ 
      for(int n = -1; n <= 1; n++){ 
       try{ 
        System.out.print(l + " "); 
        sum += mask3[l++] * Byte.toUnsignedInt((byte) source[(i + m) * height + j + n]); 
       } catch(ArrayIndexOutOfBoundsException e){ 
        int ii = (i + m) * height, jj = j + n; 
        System.out.println("Pixels[" + ii + "][" + jj + "] " + i + ", " + j); 
        System.exit(0); 
       } 
      } 
      System.out.println(); 
     } 
     System.out.println(); 
     output[i * width + j] = sum/maskSum[0]; 
    } 
} 

Я получаю source из BufferedImage так:

int[] source = image.getRGB(0, 0, width, height, null, 0, width); 

Так для этого изображения: Picture before

Результат таков: Picture after

Можете ли вы описать меня, Что случилось с моей программой?

+2

какой тип ваш '' source' и output', мы можем видеть, декларация для них? Поскольку вы делаете преобразование в байт в 'Byte.toUnsignedInt ((byte) source [(i + m) * height + j + n]), и я не могу поверить, что ваше цветное изображение будет соответствовать пикселю в один байт , Любое усечение даст вам значение max 255, которое, если оно будет преобразовано в цветовое пространство RGB с тремя байтами/образцом, объяснит, почему ваш результат синий (т. Е. Отсутствует компоненты R и G). –

+0

'int [] source = image.getRGB (0, 0, width, height, null, 0, width);' 'output' - это копия' source', поэтому мне нужно отфильтровать 3 раза? Для R и G? Как мне это сделать? – Wiszen

+1

Самый переутомный способ получить отдельные значения r, g и b - использовать (ColorModel) [https://docs.oracle.com/javase/7/docs/api/java/awt/image/ColorModel.html] Если вы знаете, как хранятся данные, вы можете извлечь 4 байта из значения int для пикселя. r = rgbVal & 0xff, g = (rgbVal >> 8) & 0xff и т. д. –

ответ

1

Прежде всего, ваша формула для вычисления индекса в исходном массиве неверна. Данные изображения сохраняются в строке массива один пиксель за другим. Поэтому индекс дается x и y рассчитываются следующим образом:

index = x + y * width 

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

следующее решение должно работать (даже если он просто оставляет пиксели в пределах прозрачных):

public static BufferedImage blur(BufferedImage image, int[] filter, int filterWidth) { 
    if (filter.length % filterWidth != 0) { 
     throw new IllegalArgumentException("filter contains a incomplete row"); 
    } 

    final int width = image.getWidth(); 
    final int height = image.getHeight(); 
    final int sum = IntStream.of(filter).sum(); 

    int[] input = image.getRGB(0, 0, width, height, null, 0, width); 

    int[] output = new int[input.length]; 

    final int pixelIndexOffset = width - filterWidth; 
    final int centerOffsetX = filterWidth/2; 
    final int centerOffsetY = filter.length/filterWidth/2; 

    // apply filter 
    for (int h = height - filter.length/filterWidth + 1, w = width - filterWidth + 1, y = 0; y < h; y++) { 
     for (int x = 0; x < w; x++) { 
      int r = 0; 
      int g = 0; 
      int b = 0; 
      for (int filterIndex = 0, pixelIndex = y * width + x; 
        filterIndex < filter.length; 
        pixelIndex += pixelIndexOffset) { 
       for (int fx = 0; fx < filterWidth; fx++, pixelIndex++, filterIndex++) { 
        int col = input[pixelIndex]; 
        int factor = filter[filterIndex]; 

        // sum up color channels seperately 
        r += ((col >>> 16) & 0xFF) * factor; 
        g += ((col >>> 8) & 0xFF) * factor; 
        b += (col & 0xFF) * factor; 
       } 
      } 
      r /= sum; 
      g /= sum; 
      b /= sum; 
      // combine channels with full opacity 
      output[x + centerOffsetX + (y + centerOffsetY) * width] = (r << 16) | (g << 8) | b | 0xFF000000; 
     } 
    } 

    BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
    result.setRGB(0, 0, width, height, output, 0, width); 
    return result; 
} 
int[] filter = {1, 2, 1, 2, 4, 2, 1, 2, 1}; 
int filterWidth = 3; 
BufferedImage blurred = blur(img, filter, filterWidth); 
+0

Большое спасибо! Эта работа так хорошо :) – Wiszen

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