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

 

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

作用,通常情况下:

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

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

常见的算子有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阶导数公式:


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


二:算法实现

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) {         					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 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

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

转载请务必注明!!!