您的位置:首页 > 其它

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

2014-09-01 23:30 483 查看
图像的一阶与二阶导数计算在图像特征提取与边缘提取中十分重要。一阶与二阶导数的

作用,通常情况下:

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

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

常见的算子有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方向效果



五:算法全部源代码:

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;

import javax.imageio.ImageIO;

public class GaussianDerivativeFilter  {

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 = 16;
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;
}

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 void setRGB(BufferedImage dest, int i, int j, int width,
int height, int[] outPixels) {
dest.setRGB( 0, 0, width, height, outPixels, 0, width );
}

private void getRGB(BufferedImage src, int i, int j, int width, int height,
int[] inPixels) {
src.getRGB(0, 0, width, height, inPixels, 0, width);
}

public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
if ( dstCM == null )
dstCM = src.getColorModel();
return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dstCM.isAlphaPremultiplied(), null);
}

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;
}

public static void main(String argv[]) throws IOException
{
GaussianDerivativeFilter gd = new GaussianDerivativeFilter();

BufferedImage src = ImageIO.read(new File("lenac.jpg"));//读取图片

BufferedImage t = gd.filter(src, null);
File file = new File("lenacy.jpg");
ImageIO.write(t, "JPEG", file);	//保存处理后的图像
}

}


该文章转自/article/1391065.html,但是我对其代码进行了部分加工,去除继承部分,增加了主函数及部分方法,可以直接进行编译运行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: