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

简介: 图像处理之高斯一阶及二阶导数计算   图像的一阶与二阶导数计算在图像特征提取与边缘提取中十分重要。一阶与二阶导数的 作用,通常情况下: 一阶导数可以反应出图像灰度梯度的变化情况 二阶导数可以提取出图像的细节同时双响应图像梯度变化情况 常见的算子有Robot, Sobel算子,二阶...

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

 

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

作用,通常情况下:

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

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

常见的算子有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; 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;
	}

}

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

转载请务必注明!!!
目录
相关文章
|
运维 监控 JavaScript
(ARMS-AIOps)一文教你用Attributor算法实现多维下钻分析
常见的AIOps应用路径为:对监控的各种关键性能指标(KPI)进行实时异常检测;对多维指标进行根源分析,快速下钻到异常维度和元素;基于应用拓扑和实时Trace,实现根因定位;结合CMDB、关联等、构建异常根因上下文,帮助快速修复问题。 作为KPI指标, 往往包含了很多维度和元素,最显而易见的则是对每一个维度的元素都进行实时异常检测。 对于维度组合笛卡尔集数量很长的场景, 该方案的成本则有点难以承受
5210 0
|
数据可视化 大数据 定位技术
I+关系网络分析发布,提供完整的可视化分析和关系引擎功能
I+关系网络分析是以OLP模型为核心,面向业务快速建模,为开发者和终端用户提供大数据关系计算引擎(含API服务)和可视化交互分析能力,面向安防、关税、银行、保险、互联网等提供的产品化方案。目前,I+关系网络分析已在阿里巴巴、蚂蚁金服集团内广泛应用于反欺诈、反作弊、反洗钱等风控业务。
4711 0
|
存储 Prometheus 运维
[10.14 workshop] 自定义 Prometheus 监控指标并通过 Grafana 展示
阿里云Prometheus监控全面对接开源Prometheus生态,支持类型丰富的组件监控,提供多种开箱即用的预置监控大盘,且提供全面托管的Prometheus服务。借助阿里云Prometheus监控,您无需自行搭建Prometheus监控系统,因而无需关心底层数据存储、数据展示、系统运维等问题。
[10.14 workshop] 自定义 Prometheus 监控指标并通过 Grafana 展示
|
机器学习/深度学习 运维 Prometheus
构建高效运维体系:从自动化部署到智能监控的全方位实践
在当今数字化时代,企业对运维效率和稳定性的要求越来越高。本文将探讨如何构建一个高效的运维体系,从自动化部署、持续集成与持续交付(CI/CD)、智能监控、故障管理以及数据驱动决策等方面进行深入分析和实践指导。通过这些方法,企业可以实现更快速、更可靠的软件发布和问题解决,提升整体运营效率。
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的自适应学习算法研究与应用
在深度学习领域,传统的静态模型在处理动态环境和非平稳数据时面临挑战。本文探讨了自适应学习算法在深度学习中的重要性及其应用。通过分析自适应学习算法在模型参数、损失函数和数据分布上的应用,展示了其在提升模型鲁棒性和泛化能力方面的潜力。具体讨论了几种代表性的自适应学习方法,并探索了它们在现实世界中的应用案例,从而展示了其在处理复杂问题和动态数据中的效果。
717 0
|
监控 算法 数据安全/隐私保护
基于视觉工具箱和背景差法的行人检测,行走轨迹跟踪,人员行走习惯统计matlab仿真
该算法基于Matlab 2022a,利用视觉工具箱和背景差法实现行人检测与轨迹跟踪,通过构建背景模型(如GMM),对比当前帧与模型差异,识别运动物体并统计行走习惯,包括轨迹、速度及停留时间等特征。演示三维图中幅度越大代表更常走的路线。完整代码含中文注释及操作视频。
|
机器学习/深度学习 人工智能 算法
开源vs闭源大模型如何塑造技术的未来?开源模型的优劣势&未来发展方向
开源vs闭源大模型如何塑造技术的未来?开源模型的优劣势&未来发展方向
1953 0
|
机器学习/深度学习 安全 Ubuntu
L4Re 小知识
L4Re 小知识
323 0
|
编解码 监控 供应链
《云上业务稳定性保障实践白皮书》——五.行业客户稳定性保障实践——5.2 直播业务稳定性保障
《云上业务稳定性保障实践白皮书》——五.行业客户稳定性保障实践——5.2 直播业务稳定性保障
314 0
|
算法 数据可视化 C++
异动分析技术解决方案—异动归因之指标拆解
归因的方法有多种,这篇文章的重点是指标拆解,也是我们做业务分析时最常用到的方法。我们的目的是解放人力,将指标拆解实现自动化,一方面可以加快业务迭代速度,快速定位问题;另一方面可以对可能产生异动的维度进行全局量化,增强可比性,明确下一步的业务行动点的优先级。自动化异变归因的目的是为了尽快判断并抓住机遇,寻求以数据驱动作为灯塔指引业务航向。
异动分析技术解决方案—异动归因之指标拆解