2013-11-08 5 views
1

Я пытаюсь сделать свой собственный оператор свертки вместо использования встроенного, который поставляется с Java. Я применил оператор встроенной свертки на этом изображении linkОператор свертки, дающий спектр цветов

используя встроенный оператор свертки с гауссовским фильтром. Я получил это изображение. link

Теперь я запускаю тот же образ, используя мой код

public static int convolve(BufferedImage a,int x,int y){ 
int red=0,green=0,blue=0; 
     float[] matrix = { 
0.1710991401561097f, 0.2196956447338621f, 0.1710991401561097f, 
0.2196956447338621f, 0.28209479177387814f, 0.2196956447338621f, 
0.1710991401561097f, 0.2196956447338621f, 0.1710991401561097f, 
}; 
     for(int i = x;i<x+3;i++){ 
      for(int j = y;j<y+3;j++){ 
       int color = a.getRGB(i,j); 
       red += Math.round(((color >> 16) & 0xff)*matrix[(i-x)*3+j-y]); 
       green += Math.round(((color >> 8) & 0xff)*matrix[(i-x)*3+j-y]); 
       blue += Math.round(((color >> 0) & 0xff)*matrix[(i-x)*3+j-y]); 

      } 
     } 

    return (a.getRGB(x, y)&0xFF000000) | (red << 16) | (green << 8) | (blue); 
} 

И В результате я получил это. link

Также как оптимизировать код, который я написал. Оператор встроенной свертки занимает 1 ~ 2 секунды, в то время как мой код, даже если он не выполняет точную цель, как предполагается, занимает 5 ~ 7 секунд!

Я случайно повернул свое исходное изображение во время загрузки. Поэтому, пожалуйста, проигнорируйте это.

ответ

1

Прежде всего, вы бесполезно (и ошибочно) преобразуете свой результат из float в int в каждом цикле цикла. Ваш red, green и blue должны быть типа поплавка и должны быть поданы обратно в целое только после того, как свертка (при преобразовании обратно в RGB):

float red=0.0f, green = 0.0f, blue = 0.0f 
    for(int i = x;i<x+3;i++){ 
     for(int j = y;j<y+3;j++){ 
      int color = a.getRGB(i,j); 
      red += ((color >> 16) & 0xff)*matrix[(i-x)*3+j-y]; 
      green += ((color >> 8) & 0xff)*matrix[(i-x)*3+j-y]; 
      blue += ((color >> 0) & 0xff)*matrix[(i-x)*3+j-y]; 

     } 
    } 

return (a.getRGB(x, y)&0xFF000000) | (((int)red) << 16) | (((int)green) << 8) | ((int)blue); 

Прокачка цветов в результате вызывается, потому что ваши коэффициенты matrix ошибается:

 
0.1710991401561097f + 0.2196956447338621f + 0.1710991401561097f + 
0.2196956447338621f + 0.28209479177387814f + 0.2196956447338621f + 
0.1710991401561097f + 0.2196956447338621f + 0.1710991401561097f = 

1.8452741 

сумма коэффициентов в размывании матрицы свертки должна быть 1,0. Когда вы применяете эту матрицу к изображению, вы можете получить цвета, превышающие 255. Когда это происходит, каналы «истекают» в следующий канал (от синего до зеленого и т. Д.). Полностью зеленое изображение с этой матрицей привело бы:

 
green = 255 * 1.8452741 ~= 471 = 0x01D7; 
rgb = 0xFF01D700; 

Который является менее интенсивный зеленый цвет с оттенком красного.

Вы можете исправить это путем деления коэффициентов на 1.8452741, но вы хотите, чтобы убедиться, что:

 
(int)(255.0f * (sum of coefficients)) = 255 

Если вам не нужно добавить проверку, которая ограничивает размер каналов до 255 и не пусть они обернутся. Например:

if (red > 255.0f) 
    red = 255.0f; 

Что касается эффективности/оптимизации:
Это может быть, что разница в скорости может быть объяснена этой ненужной отливке и вызова Math.Round, но более вероятным кандидатом является то, как вы обращаетесь изображение , Я недостаточно разбираюсь в BufferedImage и Raster, чтобы советовать вам наиболее эффективный способ доступа к базовому буферу изображений.

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