图像处理之高斯一阶及二阶导数计算

简介: 图像处理之高斯一阶及二阶导数计算

图像处理之高斯一阶及二阶导数计算

 

图像的一阶与二阶导数计算在图像特征提取与边缘提取中十分重要。一阶与二阶导数的

作用,通常情况下:

一阶导数可以反应出图像灰度梯度的变化情况

二阶导数可以提取出图像的细节同时双响应图像梯度变化情

常见的算子有Robot, Sobel算子,二阶常见多数为拉普拉斯算子,如图所示:

对于一个1D的有限集合数据f(x) = {1…N}, 假设dx的间隔为1则一阶导数计算公式如下:


Df(x) = f(x+1) – f(x-1) 二阶导数的计算公式为:df(x)= f(x+1) + f(x-1) – 2f(x);


稍微难一点的则是基于高斯的一阶导数与二阶导数求取,首先看一下高斯的1D与2D的

公式。一维高斯对应的X阶导数公式:

二维高斯对应的导数公式:

20131117130148000.png


二:算法实现


1.      高斯采样,基于间隔1计算,计算mask窗口计算,这样就跟普通的卷积计算差不多


2.      设置sigma的值,本例默认为10,首先计算高斯窗口函数,默认为3 * 3


3.      根据2的结果,计算高斯导数窗口值

4.      卷积计算像素中心点值。


注意点:计算高斯函数一定要以零为中心点, 如果窗口函数大小为3,则表达为-1, 0, 1


三:程序实现关键点


1.      归一化处理,由于高斯计算出来的窗口值非常的小,必须实现归一化处理。


2.      亮度提升,对X,Y的梯度计算结果进行了亮度提升,目的是让大家看得更清楚。


3.      支持一阶与二阶单一方向X,Y偏导数计算


四:运行效果:


高斯一阶导数X方向效果

高斯一阶导数Y方向效果


五:算法全部源代码:

/*
 * @author: gloomyfish
 * @date: 2013-11-17
 * 
 * Title - Gaussian fist order derivative and second derivative filter
 */
package com.gloomyfish.image.harris.corner;
import java.awt.image.BufferedImage;
 
import com.gloomyfish.filter.study.AbstractBufferedImageOp;
 
public class GaussianDerivativeFilter extends AbstractBufferedImageOp {
 
  public final static int X_DIRECTION = 0;
  public final static int Y_DIRECTION = 16;
  public final static int XY_DIRECTION = 2;
  public final static int XX_DIRECTION = 4;
  public final static int YY_DIRECTION = 8;
  
  // private attribute and settings
  private int DIRECTION_TYPE = 0;
  private int GAUSSIAN_WIN_SIZE = 1; // N*2 + 1
  private double sigma = 10; // default
 
  public GaussianDerivativeFilter()
  {
    System.out.println("高斯一阶及多阶导数滤镜");
  } 
  
  public int getGaussianWinSize() {
    return GAUSSIAN_WIN_SIZE;
  }
 
  public void setGaussianWinSize(int gAUSSIAN_WIN_SIZE) {
    GAUSSIAN_WIN_SIZE = gAUSSIAN_WIN_SIZE;
  }
  public int getDirectionType() {
    return DIRECTION_TYPE;
  }
 
  public void setDirectionType(int dIRECTION_TYPE) {
    DIRECTION_TYPE = dIRECTION_TYPE;
  }
 
  @Override
  public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    int width = src.getWidth();
        int height = src.getHeight();
 
        if ( dest == null )
            dest = createCompatibleDestImage( src, null );
 
        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        getRGB( src, 0, 0, width, height, inPixels );
        int index = 0, index2 = 0;
        double xred = 0, xgreen = 0, xblue = 0;
        // double yred = 0, ygreen = 0, yblue = 0;
        int newRow, newCol;
        double[][] winDeviationData = getDirectionData();
 
        for(int row=0; row<height; row++) {
          int ta = 255, tr = 0, tg = 0, tb = 0;
          for(int col=0; col<width; col++) {
            index = row * width + col;
            for(int subrow = -GAUSSIAN_WIN_SIZE; subrow <= GAUSSIAN_WIN_SIZE; subrow++) {
              for(int subcol = -GAUSSIAN_WIN_SIZE; subcol <= GAUSSIAN_WIN_SIZE; subcol++) {
                newRow = row + subrow;
                newCol = col + subcol;
                if(newRow < 0 || newRow >= height) {
                  newRow = row;
                }
                if(newCol < 0 || newCol >= width) {
                  newCol = col;
                }
                index2 = newRow * width + newCol;
                        tr = (inPixels[index2] >> 16) & 0xff;
                        tg = (inPixels[index2] >> 8) & 0xff;
                        tb = inPixels[index2] & 0xff;
                      xred += (winDeviationData[subrow + GAUSSIAN_WIN_SIZE][subcol + GAUSSIAN_WIN_SIZE] * tr);
                      xgreen +=(winDeviationData[subrow + GAUSSIAN_WIN_SIZE][subcol + GAUSSIAN_WIN_SIZE] * tg);
                      xblue +=(winDeviationData[subrow + GAUSSIAN_WIN_SIZE][subcol + GAUSSIAN_WIN_SIZE] * tb);
              }
            }
            
            outPixels[index] = (ta << 24) | (clamp((int)xred) << 16) | (clamp((int)xgreen) << 8) | clamp((int)xblue);
            
            // clean up values for next pixel
                newRow = newCol = 0;
                xred = xgreen = xblue = 0;
                // yred = ygreen = yblue = 0;
          }
        }
 
        setRGB( dest, 0, 0, width, height, outPixels );
        return dest;
  }
  
  private double[][] getDirectionData()
  {
    double[][] winDeviationData = null;
        if(DIRECTION_TYPE == X_DIRECTION)
        {
          winDeviationData = this.getXDirectionDeviation();
        }
        else if(DIRECTION_TYPE == Y_DIRECTION)
        {
          winDeviationData = this.getYDirectionDeviation();
        }
        else if(DIRECTION_TYPE == XY_DIRECTION)
        {
          winDeviationData = this.getXYDirectionDeviation();
        }
        else if(DIRECTION_TYPE == XX_DIRECTION)
        {
          winDeviationData = this.getXXDirectionDeviation();
        }
        else if(DIRECTION_TYPE == YY_DIRECTION)
        {
          winDeviationData = this.getYYDirectionDeviation();
        }
        return winDeviationData;
  }
  
  public int clamp(int value) {
    // trick, just improve the lightness otherwise image is too darker...
    if(DIRECTION_TYPE == X_DIRECTION || DIRECTION_TYPE == Y_DIRECTION)
    {
      value = value * 10 + 50;
    }
    return value < 0 ? 0 : (value > 255 ? 255 : value);
  }
  
  // centered on zero and with Gaussian standard deviation
  // parameter : sigma
  public double[][] get2DGaussianData()
  {
    int size = GAUSSIAN_WIN_SIZE * 2 + 1;
    double[][] winData = new double[size][size];
    double sigma2 = this.sigma * sigma;
    for(int i=-GAUSSIAN_WIN_SIZE; i<=GAUSSIAN_WIN_SIZE; i++)
    {
      for(int j=-GAUSSIAN_WIN_SIZE; j<=GAUSSIAN_WIN_SIZE; j++)
      {
        double r = i*1 + j*j;
        double sum = -(r/(2*sigma2));
        winData[i + GAUSSIAN_WIN_SIZE][j + GAUSSIAN_WIN_SIZE] = Math.exp(sum);
      }
    }
    return winData;
  }
  
  public double[][] getXDirectionDeviation()
  {
    int size = GAUSSIAN_WIN_SIZE * 2 + 1;
    double[][] data = get2DGaussianData();
    double[][] xDeviation = new double[size][size];
    double sigma2 = this.sigma * sigma;
    for(int x=-GAUSSIAN_WIN_SIZE; x<=GAUSSIAN_WIN_SIZE; x++)
    {
      double c = -(x/sigma2);
      for(int i=0; i<size; i++)
      {
        xDeviation[i][x + GAUSSIAN_WIN_SIZE] = c * data[i][x + GAUSSIAN_WIN_SIZE];        
      }
    }
    return xDeviation;
  }
  
  public double[][] getYDirectionDeviation()
  {
    int size = GAUSSIAN_WIN_SIZE * 2 + 1;
    double[][] data = get2DGaussianData();
    double[][] yDeviation = new double[size][size];
    double sigma2 = this.sigma * sigma;
    for(int y=-GAUSSIAN_WIN_SIZE; y<=GAUSSIAN_WIN_SIZE; y++)
    {
      double c = -(y/sigma2);
      for(int i=0; i<size; i++)
      {
        yDeviation[y + GAUSSIAN_WIN_SIZE][i] = c * data[y + GAUSSIAN_WIN_SIZE][i];        
      }
    }
    return yDeviation;
  }
  
  /***
   * 
   * @return
   */
  public double[][] getXYDirectionDeviation()
  {
    int size = GAUSSIAN_WIN_SIZE * 2 + 1;
    double[][] data = get2DGaussianData();
    double[][] xyDeviation = new double[size][size];
    double sigma2 = sigma * sigma;
    double sigma4 = sigma2 * sigma2;
    // TODO:zhigang
    for(int x=-GAUSSIAN_WIN_SIZE; x<=GAUSSIAN_WIN_SIZE; x++)
    {
      for(int y=-GAUSSIAN_WIN_SIZE; y<=GAUSSIAN_WIN_SIZE; y++)
      {
        double c = -((x*y)/sigma4);
        xyDeviation[x + GAUSSIAN_WIN_SIZE][y + GAUSSIAN_WIN_SIZE] = c * data[x + GAUSSIAN_WIN_SIZE][y + GAUSSIAN_WIN_SIZE];
      }
    }
    return normalizeData(xyDeviation);
  }
  
  private double[][] normalizeData(double[][] data)
  {
    // normalization the data
    double min = data[0][0];
    for(int x=-GAUSSIAN_WIN_SIZE; x<=GAUSSIAN_WIN_SIZE; x++)
    {
      for(int y=-GAUSSIAN_WIN_SIZE; y<=GAUSSIAN_WIN_SIZE; y++)
      {
        if(min > data[x + GAUSSIAN_WIN_SIZE][y + GAUSSIAN_WIN_SIZE])
        {
          min = data[x + GAUSSIAN_WIN_SIZE][y + GAUSSIAN_WIN_SIZE];
        }
      }
    }
    
    for(int x=-GAUSSIAN_WIN_SIZE; x<=GAUSSIAN_WIN_SIZE; x++)
    {
      for(int y=-GAUSSIAN_WIN_SIZE; y<=GAUSSIAN_WIN_SIZE; y++)
      {
        data[x + GAUSSIAN_WIN_SIZE][y + GAUSSIAN_WIN_SIZE] = data[x + GAUSSIAN_WIN_SIZE][y + GAUSSIAN_WIN_SIZE] /min;
      }
    }
    
    return data;
  }
  
  public double[][] getXXDirectionDeviation()
  {
    int size = GAUSSIAN_WIN_SIZE * 2 + 1;
    double[][] data = get2DGaussianData();
    double[][] xxDeviation = new double[size][size];
    double sigma2 = this.sigma * sigma;
    double sigma4 = sigma2 * sigma2;
    for(int x=-GAUSSIAN_WIN_SIZE; x<=GAUSSIAN_WIN_SIZE; x++)
    {
      double c = -((x - sigma2)/sigma4);
      for(int i=0; i<size; i++)
      {
        xxDeviation[i][x + GAUSSIAN_WIN_SIZE] = c * data[i][x + GAUSSIAN_WIN_SIZE];       
      }
    }
    return xxDeviation;
  }
  
  public double[][] getYYDirectionDeviation()
  {
    int size = GAUSSIAN_WIN_SIZE * 2 + 1;
    double[][] data = get2DGaussianData();
    double[][] yyDeviation = new double[size][size];
    double sigma2 = this.sigma * sigma;
    double sigma4 = sigma2 * sigma2;
    for(int y=-GAUSSIAN_WIN_SIZE; y<=GAUSSIAN_WIN_SIZE; y++)
    {
      double c = -((y - sigma2)/sigma4);
      for(int i=0; i<size; i++)
      {
        yyDeviation[y + GAUSSIAN_WIN_SIZE][i] = c * data[y + GAUSSIAN_WIN_SIZE][i];       
      }
    }
    return yyDeviation;
  }
 
}

国足都战胜亚洲强队印尼了,我还有什么理由不坚持写下去!

转载请务必注明!!!

相关文章
|
移动开发 算法
科学计算与仿真-高斯牛顿法的非线性最小二乘问题简单介绍与应用
科学计算与仿真-高斯牛顿法的非线性最小二乘问题简单介绍与应用
690 0
科学计算与仿真-高斯牛顿法的非线性最小二乘问题简单介绍与应用
|
6月前
|
Java API 计算机视觉
图像处理之添加高斯与泊松噪声
图像处理之添加高斯与泊松噪声
72 1
|
6月前
|
计算机视觉
图像处理之一阶微分应用
图像处理之一阶微分应用
41 0
|
6月前
|
Java API 计算机视觉
图像处理之形态学梯度计算
图像处理之形态学梯度计算
60 0
|
机器学习/深度学习 传感器 算法
基于matlab计算不等间距样本的一阶和二阶导数
基于matlab计算不等间距样本的一阶和二阶导数
|
机器学习/深度学习 传感器 算法
【光学】基于GS算法实现高斯光转换成高阶高斯光,一阶空心高斯光,贝塞尔高斯光附matlab代码
【光学】基于GS算法实现高斯光转换成高阶高斯光,一阶空心高斯光,贝塞尔高斯光附matlab代码
|
机器学习/深度学习 算法 计算机视觉
【智能优化算法-正弦余弦算法】基于正弦余弦算法求解高维优化问题附matlab代码
【智能优化算法-正弦余弦算法】基于正弦余弦算法求解高维优化问题附matlab代码
【智能优化算法-正弦余弦算法】基于正弦余弦算法求解高维优化问题附matlab代码