图像的一阶微分算子

概述

二元函数f(x,y)的一阶微分为fx=ʚf/ʚxfx=ʚf/ʚy,图像的坐标表示如下:

假设一张图片的各像素为:

3 33333

355553

3 5 9 9 5 3

3 5 9 9 5 3

355553

3 33333

在往下进行介绍之前,先给出两个读图片和写图片的函数

算法源代码1(读图片和写图片)

/**
	 * 读取图片
	 * @param srcPath 图片的存储位置
	 * @return 返回图片的BufferedImage对象
	 */
	public static BufferedImage readImg(String srcPath) {
		BufferedImage img = null;
		try {
			img = ImageIO.read(new File(srcPath));			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return img;
	}
	/**
	 * 将图片写入磁盘
	 * @param img 图像的BufferedImage对象
	 * @param formatName 存储的文件格式
	 * @param distPath 图像要保存的存储位置
	 */
	public static void writeImg(BufferedImage img, String formatName, String distPath) {
		OutputStream out = null;
		try {
			//int imgType = img.getType();			
			//System.out.println("w:" + img.getWidth() + "  h:" + img.getHeight());
			out = new FileOutputStream(distPath);			
			ImageIO.write(img, formatName, out);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(out != null) {
					out.close();
				}				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	} 


水平微分算子

水平方向的微分算子是要获得图像在水平方向上的变化率。

定义

G=f(x-1,y-1)+2f(x,y-1)+f(x+1,y-1)–f(x-1,y+1)–2f(x,y+1)–f(x+1,y+1)

权系数矩阵模板


水平方向的微分算子处理结果:

0 0 0 0 0 0

0 -10 -20 -20 -10 0

0 -4 -12 -12 -4 0

0 4 12 12 4 0

0 10 20 20 10 0

0 0 0 0 0 0

为了能够正常显示处理后结果,将每个像素加上最小值的绝对值(如上面的|-20|),结果如下:

20 20 20 20 20 20

20 10 0 0 10 20

20 16 8 8 16 20

20 24 32 32 24 20

20 30 40 40 30 20

20 20 20 20 20 20

算法源代码2

/**
	 * 水平微分算子
	* @param srcPath 图片的存储位置
	 * @param distPath 图像要保存的存储位置
	 * @param formatName 图像要保存的存储位置
	 */
	public static void firstMomentX(String srcPath, String distPath, String formatName) {
		BufferedImage img = readImg(srcPath);		
		int w = img.getWidth();
		int h = img.getHeight();
		int pix[] = new int[w*h];
		        pix= img.getRGB(0, 0, w, h, pix, 0, w);
		pix = firstMomentX(pix, w, h);
		img.setRGB(0, 0, w, h, pix, 0, w);
		writeImg(img, formatName, distPath);
	}
	/**
	 * 水平微分算子
	 * @param pix 像素矩阵数组
	 * @param w 矩阵的宽
	 * @param h 矩阵的高
	 * @return 处理后的数组
	 */
	public static int[] firstMomentX(int[] pix, int w, int h) {
		int[] newpix = new int[w*h];
		ColorModel cm = ColorModel.getRGBdefault();
		int r, g, b;
		for(int y=0; y<h; y++) {
			for(int x=0; x<w; x++) {
				if(x!=0 && x!=w-1 && y!=0 && y!=h-1){
					//G=f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1) – f(x-1,y+1) – 2f(x,y+1) – f(x+1,y+1)
					r = cm.getRed(pix[x-1+(y-1)*w]) + 2* cm.getRed(pix[x+(y-1)*w]) +  cm.getRed(pix[x+1+(y-1)*w]) 
					              -  cm.getRed(pix[x-1+(y+1)*w]) - 2* cm.getRed(pix[x+(y+1)*w]) -  cm.getRed(pix[x+1+(y+1)*w]);
					 newpix[x+y*w] = 255<<24 | r<<16 | r<<8 | r;
				}					
			}
		}
		int temp = findMinInt(newpix);
		for(int i=0; i<newpix.length; i++) {
			newpix[i] = newpix[i] + temp;
		}
		return newpix;
	}


垂直微分算子

水平方向的微分算子是要获得图像在水平方向上的变化率。

定义

G=f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1)-f(x+1,y-1)-2f(x+1,y)-f(x+1,y+1)

权系数矩阵模板


垂直方向的微分算子处理结果:

20 20 20 20 20 20

20 10 16 24 30 20

20 0 8 32 40 20

20 0 8 32 40 20

20 10 16 24 30 20

20 20 20 20 20 20

算法源代码3

/**
	 * 垂直微分算子
	* @param srcPath 图片的存储位置
	 * @param distPath 图像要保存的存储位置
	 * @param formatName 图像要保存的存储位置
	 */
	public static void firstMomentY(String srcPath, String distPath, String formatName) {
		BufferedImage img = readImg(srcPath);		
		int w = img.getWidth();
		int h = img.getHeight();
		int pix[] = new int[w*h];
		        pix= img.getRGB(0, 0, w, h, pix, 0, w);
		pix = firstMomentY(pix, w, h);
		img.setRGB(0, 0, w, h, pix, 0, w);
		writeImg(img, formatName, distPath);
	}
	/**
	 * 垂直微分算子
	* @param pix 像素矩阵数组
	 * @param w 矩阵的宽
	 * @param h 矩阵的高
	 * @return 处理后的数组
	 */
	public static int[] firstMomentY(int[] pix, int w, int h) {
		int[] newpix = new int[w*h];
		ColorModel cm = ColorModel.getRGBdefault();
		int r;
		for(int y=0; y<h; y++) {
			for(int x=0; x<w; x++) {
				if(x!=0 && x!=w-1 && y!=0 && y!=h-1) {
					//G=f(x-1,y-1) + 2f(x-1,y) + f(x-1,y+1) - f(x+1,y-1) - 2f(x+1,y) - f(x+1, y+1)
					/*newpix[x+y*w] = pix[x-1+(y-1)*w] + 2*pix[x-1+(y)*w] + pix[x-1+(y+1)*w]
					              - pix[x+1+(y-1)*w] - 2*pix[x+1+(y)*w] - pix[x+1+( y+1)*w];*/
					r = cm.getRed(pix[x-1+(y-1)*w]) + 2*cm.getRed(pix[x-1+(y)*w]) + cm.getRed(pix[x-1+(y+1)*w])
					                - cm.getRed(pix[x+1+(y-1)*w]) - 2*cm.getRed(pix[x+1+(y)*w]) - cm.getRed(pix[x+1+( y+1)*w]);
					newpix[x+y*w] = 255<<24 | r<<16 | r<<8 | r;
				}
			}
		}
		int temp = findMinInt(newpix);
		for(int i=0; i<newpix.length; i++) {
			newpix[i] = newpix[i] + temp;
		}
		return newpix;
	}


实验效果:

原图:


水平方向的微分算子的效果


垂直方向的微分算子的效果

Roberts交叉微分算子

水平微分算子和垂直微分算子只求出了特定方向上的细节信息,但是对于大多数图像来说,求出细节轮廓是一全非常重要的信息,而往往遇到的大部分景物的细节是不规则的,所以在二维图像的两个方向上来考虑锐化微分是很有必要的。Roberts叉微分算子的作用模板如下:


定义:

G=|f(x+1,y+1)-f(x,y)|+|f(x,y+1)-f(x+1,y)|

权系数矩阵模板


F1’=D1(f(x,y)),F2’=D2(f(x,y))

G=|F1’|+|F2’|

算法源代码4

/**
	 * Roberts交叉微分算子
	 * @param srcPath 图片的存储位置
	 * @param distPath 图像要保存的存储位置
	 * @param formatName 图像要保存的存储位置
	 */
	public static void roberts(String srcPath, String distPath, String formatName) {
		BufferedImage img = readImg(srcPath);		
		int w = img.getWidth();
		int h = img.getHeight();
		int pix[] = new int[w*h];
		        pix= img.getRGB(0, 0, w, h, pix, 0, w);
		pix = roberts(pix, w, h);
		img.setRGB(0, 0, w, h, pix, 0, w);
		writeImg(img, formatName, distPath);
	}
	/**
	 * Roberts交叉微分算子
	 * @param pix 像素矩阵数组
	 * @param w 矩阵的宽
	 * @param h 矩阵的高
	 * @return 处理后的像素矩阵
	 */
	public static int[] roberts(int pix[], int w, int h) {
		ColorModel cm = ColorModel.getRGBdefault();
		int r;
		int[] newpix = new int[w*h];
		for(int y=0; y<h; y++) {
			for(int x=0; x<w; x++) {
				if(x!=w-1 && y!=h-1){
					//G=|f(x+1,y+1) - f(x,y)| + |f(x,y+1)-f(x+1,y)|
					r=Math.abs(cm.getRed(pix[x+1+(y+1)*w]) - cm.getRed(pix[x+y*w])) +
					  Math.abs(cm.getRed(pix[x+(y+1)*w]) - cm.getRed(pix[x+1+y*w]));
					newpix[x+y*w] = 255<<24 | r<<16 | r <<8 | r;
				} else {
					if(x == w-1) {
						newpix[x+y*w] = pix[x-1+y*w];
					}
					if(y == h-1) {
						newpix[x+y*w] = pix[x+(y-1)*w];
					}
				}
			}
		}		
		return newpix;
	}


效果:


Sobel微分算子

前面介绍的Roberts微分算子可以获得景物的细节轮廓,且模板小,计算量小;但由于模板的尺寸是偶数,待处理的像素不能放在模板中心。Sobel微分算子是一种奇数大小(3*3)模板下的全方向微分算子。

定义:

D1=f(x-1,y-1)+2f(x,y-1)+f(x+1,y-1)–f(x-1,y+1)–2f(x,y+1)–f(x+1,y+1)

D2=f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1)–f(x+1,y-1)–2f(x+1,y)–f(x+1,y+1)

G=sqrt(D1^2+D2^2)

算法源代码5

/**
	 * Sobel微分算子
	 * @param srcPath 图片的存储位置
	 * @param distPath 图像要保存的存储位置
	 * @param formatName 图像要保存的存储位置
	 */
	public static void sobel(String srcPath, String distPath, String formatName) {
		BufferedImage img = readImg(srcPath);		
		int w = img.getWidth();
		int h = img.getHeight();
		int pix[] = new int[w*h];
		        pix= img.getRGB(0, 0, w, h, pix, 0, w);
		pix = sobel(pix, w, h);
		img.setRGB(0, 0, w, h, pix, 0, w);
		writeImg(img, formatName, distPath);
	}
	/**
	 * Sobel微分算子
	 * @param pix 像素矩阵数组
	 * @param w 矩阵的宽
	 * @param h 矩阵的高
	 * @return 处理后的像素矩阵
	 */
	public static int[] sobel(int pix[], int w, int h) {
		ColorModel cm = ColorModel.getRGBdefault();
		int g1, g2, r;
		int[] newpix = new int[w*h];
		for(int y=0; y<h; y++) {
			for(int x=0; x<w; x++) {
				if(x!=0 && x!=w-1 && y!=0 && y!=h-1){
					//G
					g1 = cm.getRed(pix[x-1+(y-1)*w]) + 2* cm.getRed(pix[x+(y-1)*w]) +  cm.getRed(pix[x+1+(y-1)*w]) 
		                 - cm.getRed(pix[x-1+(y+1)*w]) - 2* cm.getRed(pix[x+(y+1)*w]) -  cm.getRed(pix[x+1+(y+1)*w]);
					g2 = cm.getRed(pix[x-1+(y-1)*w]) + 2*cm.getRed(pix[x-1+(y)*w]) + cm.getRed(pix[x-1+(y+1)*w])
	                     - cm.getRed(pix[x+1+(y-1)*w]) - 2*cm.getRed(pix[x+1+(y)*w]) - cm.getRed(pix[x+1+( y+1)*w]);
					r=(int) Math.round(Math.sqrt(g1*g1 + g2*g2));
					newpix[x+y*w] = 255<<24 | r<<16 | r <<8 | r;
				} else {
					if(x == w-1) {
						newpix[x+y*w] = pix[x-1+y*w];
					}
					if(y == h-1) {
						newpix[x+y*w] = pix[x+(y-1)*w];
					}
				}
			}
		}		
		return newpix;
	}


效果:

Priwitt微分算子

Priwitt微分算子与Sobel微分算子类似,是一个奇数大小(3*3)的模板中定义其微分算子。只是模板系数不同。

D1=f(x-1,y-1)+2f(x,y-1)+f(x+1,y-1)–f(x-1,y+1)–2f(x,y+1)–f(x+1,y+1)

D2=f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1)–f(x+1,y-1)–2f(x+1,y)–f(x+1,y+1)

G=sqrt(D1^2+D2^2)

算法源代码6

/**
	 * priwitt微分算子
	 * @param srcPath 图片的存储位置
	 * @param distPath 图像要保存的存储位置
	 * @param formatName 图像要保存的存储位置
	 */
	public static void priwitt(String srcPath, String distPath, String formatName) {
		BufferedImage img = readImg(srcPath);		
		int w = img.getWidth();
		int h = img.getHeight();
		int pix[] = new int[w*h];
		        pix= img.getRGB(0, 0, w, h, pix, 0, w);
		pix = priwitt(pix, w, h);
		img.setRGB(0, 0, w, h, pix, 0, w);
		writeImg(img, formatName, distPath);
	}
	/**
	 * priwitt微分算子
	 * @param pix 像素矩阵数组
	 * @param w 矩阵的宽
	 * @param h 矩阵的高
	 * @return 处理后的像素矩阵
	 */
	public static int[] priwitt(int pix[], int w, int h) {
		ColorModel cm = ColorModel.getRGBdefault();
		int g1, g2, r;
		int[] newpix = new int[w*h];
		for(int y=0; y<h; y++) {
			for(int x=0; x<w; x++) {
				if(x!=0 && x!=w-1 && y!=0 && y!=h-1){
					//G
					g1 = cm.getRed(pix[x-1+(y-1)*w]) + cm.getRed(pix[x+(y-1)*w]) +  cm.getRed(pix[x+1+(y-1)*w]) 
		                 - cm.getRed(pix[x-1+(y+1)*w]) - cm.getRed(pix[x+(y+1)*w]) -  cm.getRed(pix[x+1+(y+1)*w]);
					g2 = cm.getRed(pix[x-1+(y-1)*w]) + cm.getRed(pix[x-1+(y)*w]) + cm.getRed(pix[x-1+(y+1)*w])
	                     - cm.getRed(pix[x+1+(y-1)*w]) - cm.getRed(pix[x+1+(y)*w]) - cm.getRed(pix[x+1+( y+1)*w]);
					r=(int) Math.round(Math.sqrt(g1*g1 + g2*g2));
					newpix[x+y*w] = 255<<24 | r<<16 | r <<8 | r;
				} else {
					if(x == w-1) {
						newpix[x+y*w] = pix[x-1+y*w];
					}
					if(y == h-1) {
						newpix[x+y*w] = pix[x+(y-1)*w];
					}
				}
			}
		}		
		return newpix;
	}

效果:


### 微分算子的结合方法与数学运算 #### 数学基础 在微分算子的应用中,其核心思想是对图像中的灰度变化进行检测。由于数字图像是离散的数据形式,因此无法直接计算连续函数的导数,而是采用差分来近似表示微分操作[^1]。具体来说,对于二维图像 \( f(x, y) \),可以通过以下两种方式实现: - **水平方向的差分**: 表达式为 \( G_x = f(x+1, y) - f(x, y) \)[^1]。 - **垂直方向的差分**: 表达式为 \( G_y = f(x, y+1) - f(x, y) \)[^1]。 最终的结果可以组合成梯度向量的形式: \[ \nabla f = (G_x, G_y) \] 或者通过模值计算得到边缘强度: \[ |\nabla f| = \sqrt{G_x^2 + G_y^2} \] 为了简化计算,在实际应用中通常会使用绝对值替代平方根运算: \[ |\nabla f| = |G_x| + |G_y| \][^2]。 --- #### 经典微分算子及其结合方式 以下是几种常见的微分算子以及它们如何结合到具体的场景中: ##### 1. 罗伯特算子(Roberts Cross) 罗伯特算子种简单的斜向差分算子,用于快速估算图像的梯度。它由两个模板组成,分别对应于正对角线和负对角线的方向差异。 ```python import numpy as np roberts_cross_v = np.array([[1, 0], [0, -1]]) roberts_cross_h = np.array([[0, 1], [-1, 0]]) def apply_roberts(image): grad_v = np.abs(np.convolve(image, roberts_cross_v)) grad_h = np.abs(np.convolve(image, roberts_cross_h)) gradient_magnitude = grad_v + grad_h return gradient_magnitude ``` ##### 2. Prewitt 算子 Prewitt 算子扩展了罗伯特算子的思想,增加了更多的邻域像素参与计算,从而提高了抗噪能力。 ```python prewitt_x = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]]) prewitt_y = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]]) ``` ##### 3. Sobel 算子 Sobel 算子步优化了权重分配方案,使得中心像素的影响更大,能够更好地捕捉边界信息。 ```python sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]) sobel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]]) ``` ##### 4. Scharr 算子 Scharr 算子相较于 Sobel 算子具有更高的精度,尤其适合噪声较大的情况。 ```python scharr_x = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]]) scharr_y = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]]) ``` --- #### 应用场景分析 微分算子广泛应用于计算机视觉领域,特别是在以下几个方面发挥了重要作用: 1. **边缘检测**:通过对图像亮度的变化率进行测量,提取物体轮廓或区域分割的关键特征。 2. **纹理识别**:基于局部梯度分布特性描述表面结构属性,帮助区分不同材质类型的样本。 3. **运动估计**:利用时间序列帧间差异配合空间维度上的偏导数值共同构建光流场模型。 4. **增强处理**:作为高通滤波的部分,强化高频成分以突出细节部分并改善视觉效果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值