2016-02-16 5 views
1

У меня есть изображение с большим количеством сглаженных линий в нем и попытка удалить пиксели, которые опускаются ниже определенного порога альфа-канала (и что-то выше порогового значения преобразуется в полный 255 альфа). У меня это закодировано и работает, его просто не так быстро, как хотелось бы при запуске на больших изображениях. Кто-нибудь может предложить альтернативный метод?Java - удалять пиксели ниже определенного значения альфа

//This will convert all pixels with > minAlpha to 255 
public static void flattenImage(BufferedImage inSrcImg, int minAlpha) 
{ 
    //loop through all the pixels in the image 
    for (int y = 0; y < inSrcImg.getHeight(); y++) 
    { 
     for (int x = 0; x < inSrcImg.getWidth(); x++) 
     { 
      //get the current pixel (with alpha channel) 
      Color c = new Color(inSrcImg.getRGB(x,y), true); 

      //if the alpha value is above the threshold, convert it to full 255 
      if(c.getAlpha() >= minAlpha) 
      { 
       inSrcImg.setRGB(x,y, new Color(c.getRed(), c.getGreen(), c.getBlue(), 255).getRGB()); 
      } 
      //otherwise set it to 0 
      else 
      { 
       inSrcImg.setRGB(x,y, new Color(0,0,0,0).getRGB()); //white (transparent) 
      } 
     } 
    } 
} 

на комментарии @BenoitCoudour «s Я изменил код, соответственно, но, как представляется, влияет на результирующие значения RGB пикселей, любую идею, что я могу делать неправильно?

public static void flattenImage(BufferedImage src, int minAlpha) 
{ 
    int w = src.getWidth(); 
    int h = src.getHeight(); 

    int[] rgbArray = src.getRGB(0, 0, w, h, null, 0, w); 

    for (int i=0; i<w*h; i++) 
    { 
     int a = (rgbArray[i] >> 24) & 0xff; 
     int r = (rgbArray[i] >> 16) & 0xff; 
     int b = (rgbArray[i] >> 8) & 0xff; 
     int g = rgbArray[i] & 0xff; 

     if(a >= minAlpha) { rgbArray[i] = (255<<24) | (r<<16) | (g<<8) | b; } 
     else { rgbArray[i] = (0<<24) | (r<<16) | (g<<8) | b; } 
    } 

    src.setRGB(0, 0, w, h, rgbArray, 0, w); 
} 
+1

Вы читаете ARBG, но записываете ARGB. Вы должны также прочитать ARGB. Другими словами, вы читаете зеленое значение в 'b', а синее значение -' g'. – erickson

+0

Если ваш 'BufferedImage' имеет тип' TYPE_INT_ARGB', методы 'getRGB/setRGB (...)' излишне медленны. Быстрее обращаться к массиву данных резервного копирования напрямую. – haraldK

ответ

1

Что может мешать вам создать экземпляр объекта Color для каждого пикселя. Пожалуйста, смотрите этот ответ перебрать пикселей в BufferedImage и получить доступ к альфа-канал: https://stackoverflow.com/a/6176783/3721907

Я просто вставить код ниже

public Image alpha2gray(BufferedImage src) { 

    if (src.getType() != BufferedImage.TYPE_INT_ARGB) 
     throw new RuntimeException("Wrong image type."); 

    int w = src.getWidth(); 
    int h = src.getHeight(); 

    int[] srcBuffer = src.getData().getPixels(0, 0, w, h, null); 
    int[] dstBuffer = new int[w * h]; 

    for (int i=0; i<w*h; i++) { 
     int a = (srcBuffer[i] >> 24) & 0xff; 
     dstBuffer[i] = a | a << 8 | a << 16; 
    } 

    return Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(w, h, pix, 0, w)); 
} 

Это очень близко к тому, что вы хотите достигать.

+0

Этот вызов возвращается неоднозначно, он ожидает int [] или float [] в последнем члене. Не совсем уверен, что я должен там использовать. int [] srcBuffer = src.getData(). GetPixels (0, 0, w, h, null); – cdubbs

+0

Да, код не компилируется ... Попробуйте это int [] srcBuffer = src.getData(). GetPixels (0, 0, w, h, new int [w * h]); –

0

У вас есть теоретическая сложность O(n), которую вы оптимизируете, выполняя манипуляции с байтами.

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

Поскольку я уже упоминал, что у вас проблема с неловкой параллельностью, лучшим решением является выполнение программирования графического процессора.

Вы можете читать этот учебник по simple image processing with cuda и изменить код фильтра на что-то вроде этого

void blur(unsigned char* input_image, unsigned char* output_image, int width, int height) { 

const unsigned int offset = blockIdx.x*blockDim.x + threadIdx.x; 
const int currentoffset = (offset)*4; 
if(offset < width*height) { 
      if (input_image[currentoffset+3]>= threshold) 
       output_red = input_image[currentoffset]; 
       output_green = input_image[currentoffset+1]; 
       output_blue = input_image[currentoffset+2]; 
       output_alpha = 255; 
      }else{ 
       output_red = 0; 
       output_green = 0; 
       output_blue = 0; 
       output_alpha = 0; 
      } 
     } 
    } 
    output_image[currentoffset*3] = output_red; 
    output_image[currentoffset*3+1] = output_green; 
    output_image[currentoffset*3+2] = output_blue; 
    output_image[currentoffset*3+3] = output_alpha 
    } 

}

Если вы настроены на использование Java вы здесь большой ответ о том, как начало работы на using java with nvidia gpu

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