图像增强之拉普拉斯锐化---高斯一阶导二阶导数

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

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

作用,通常情况下:

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

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

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

五:算法全部源代码:

[java] view plaincopy

    1. /*
      * @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;
      }

      }

    2. http://blog.csdn.net/jia20003/article/details/16369143
时间: 2024-10-03 22:32:18

图像增强之拉普拉斯锐化---高斯一阶导二阶导数的相关文章

正交梯度算子(一阶导)

在边缘灰度值过度比较尖锐切图像中噪声比较小时,梯度算子工作效果好. 1.数字图像中求导数是利用差分近似微分来进行的. 2.梯度对应一阶导,梯度是矢量. 矢量的幅度(有时候常称为梯度) 方向角: 注意:范数的概念,实际上就是一种求距离的方法,详见距离度量函数 幅度有这里用欧式距离是2范数,城区距离是1范数,∞范数是棋盘距离. 实际计算中先计算每个图片对应点的(Gx,Gy),然后求范数,范数的值就是灰度图,范数大灰度高的地方是边界. 一般地,计算Gx,Gy都有两个模板,分别对图片做两次卷积,然后再求

图像处理URL

随笔分类 - 图像处理/图像增强等 图像增强: 图像复原: 图像重建: 图像分割: 图像特效: 图像匹配: 图像形态学处理: 图像几何处理: 图像正交变换: 人工智能: 跟踪: 图像处理之增强---图像模糊检测 摘要: 这种检测可以做宽动态的检测,也可应用稳像算法我们实现了拉普拉斯方差算法,该算法提供给我们一个浮点数来代表具体图像的"模糊度".该算法快速,简单且易于使用--用拉普拉斯算子与输入图像做卷积然后计算方差即可.如果方差低于预定义阈值,图像就被标记为"模糊"

图像锐化

图像边缘分析 一阶微分算子 一梯度算子 二Robert算子 三Sobel算子 四Prewitt算子 二阶微分算子 高斯滤波和边缘检测 一高斯函数 二LOG算子 三Canny算子 频域高通滤波 图像边缘分析 边缘定义为图像中亮度突变的区域,分为:细线型边缘.突变型边缘和渐变型边缘 1)突变型边缘位于图像中具有不同灰度值的相邻区域之间,对应于一阶导数的极值和二阶导数的过零点 2)细线型边缘对应于灰度变化曲线的极值,对应于一阶导数的过零点和二阶微分的极值点 2)渐进型边缘因变化缓慢,没有明确的边界点

【Tadeas】图片特征

特征提取 直方图 用于计算图片的特征(Feature) 和表达(representation) 对图片数据/特征分别的一种统计 ** 灰度.颜色 ** 梯度/边缘.形状.纹理 ** 局部特征点.视觉词汇 区间(bin) ** 均有一定的统计或者物理意义 ** 一种数据或者特征的代表 ** 需要预定义或者基于数据进行学习 ** 数值是一种统计量: 概率.频数.特定积累 维度小于原始数据 对数据空间(Bin)进行量化 人工分割 人工分割:简单高效,但是存在量化问题,量化过宽容易造成精度的损失或者量化

使用二阶微分锐化图像(拉普拉斯算子)基本原理及Python实现

1. 拉普拉斯算子 1.1 简介 一种典型的各向同性的微分算子,可用于检测图像中灰度图片的区域 $$ \nabla^{2} f=\frac{\partial^{2} f}{\partial x^{2}}+\frac{\partial^{2} f}{\partial y^{2}} $$ 根据上述的差分近似可以推导出 $$ \nabla^{2} f(x, y)=f(x+1, y)+f(x-1, y)+f(x, y+1)+f(x, y-1)-4 f(x, y) $$ 1.2 锐化过程 使用拉普拉斯过滤

中值滤波与图像锐化

本文主要包括以下内容 中值滤波及其改进算法 图像锐化, 包括梯度算子.拉普拉斯算子.高提升滤波和高斯-拉普拉斯变换 本章的典型囊例分析 对椒盐噪声的平滑效果比较 Laplacian与LoG算子的锐化效果比较 中值滤波 中值滤波本质上是一种统计排序滤波器. 对于原图像中某点(i,j), 中值滤波以该点为中 心的邻域内的所有像素的统计排序中值作为(i, j) 点的响应. 中值不同于均值, 是指排序队列中位于中间位置的元素的值,例如=采用3x3 中值滤披 器, 某点.(i,j) 的8 个邻域的一系列像

图像增强相关基础知识

图像增强处理-1 图像增强是图像处理中一个重要的内容,在图像生成,传输或变换的过程中,由于多种因素的影响,造成图像质量下降,图像模糊,特征淹没,给分析和识别带来困难.因此,按特定的需要将图像中感兴趣的特征友选择地突出,衰减不需要的特征,提高图像的可懂度是图像增强的主要内容.图像增强不考虑图像降质的原因,而且改善后的图像也不一定逼近原图像,这是它与图像复原本质的区别.图像增强的主要目的有两个:一是改善图像的视觉效果,提高图像的清晰度:二是将图像转换成一种更适合人类或机器进行分析处理的形式,一边从图

paper 109 :图像处理中的拉普拉斯算子

1.基本理论 拉普拉斯算子是最简单的各向同性微分算子,具有旋转不变性.一个二维图像函数 的拉普拉斯变换是各向同性的二阶导数,定义为:   为了更适合于数字图像处理,将该方程表示为离散形式:    另外,拉普拉斯算子还可以表示成模板的形式,如图5-9所示.图5-9(a)表示离散拉普拉斯算子的模板,图5-9(b)表示其扩展模板,图5-9(c)则分别表示其他两种拉普拉斯的实现模板.从模板形式容易看出,如果在图像中一个较暗的区域中出现了一个亮点,那么用拉普拉斯运算就会使这个亮点变得更亮.因为图像中的边缘

SIFT四部曲之——高斯滤波

本文为原创作品,未经本人同意,禁止转载 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和http://www.cnblogs.com/xujianqing/ 或许网络上有各位牛人已经对sift算法进行各种的详解和说明,我(小菜鸟)在翻阅各种资料和对opencv中的代码进行反推之后,终于理解该算法.并记录之,供大家一起交流学习!这个博文主要记录了我的学习历程,或许对你有帮助,或许可以启发你,或许你只是一笑而过!没关系,至少自己总结过. 这篇文章主要是对sif