# 图像处理梯度算子2*2

## 图像处理之图像梯度效果

2012-06-14 23:05:48 jia20003 阅读数 48113
• ###### 图像梯度

掌握OpenCV核心模块，熟练使用相关API 理解各个API背后的相关算法原理，每个参数意义 有能力解决使用应用场景问题，大量工程代码经验分享 掌握图像处理与视频分析，图像分析与测量编码与开发技巧

98人学习 贾志刚
免费试看

Prewitt在X, Y方向上梯度算子分别为：

– 方向，用来要决定图像完成X方向梯度计算， Y方向梯度计算，或者是振幅计算

– 算子类型，用来决定是使用sobel算子或者是prewitt算子。

三：运行效果

package com.process.blur.study;

import java.awt.image.BufferedImage;
/**
*
* @author gloomy-fish
* @date 2012-06-11
*
* prewitt operator
* X-direction
* -1, 0, 1
* -1, 0, 1
* -1, 0, 1
*
* Y-direction
* -1, -1, -1
*  0,  0,  0
*  1,  1,  1
*
* sobel operator
* X-direction
* -1, 0, 1
* -2, 0, 2
* -1, 0, 1
*
* Y-direction
* -1, -2, -1
*  0,  0,  0
*  1,  2,  1
*
*/
public class GradientFilter extends AbstractBufferedImageOp {

// prewitt operator
public final static int[][] PREWITT_X = new int[][]{{-1, 0, 1}, {-1, 0, 1}, {-1, 0, 1}};
public final static int[][] PREWITT_Y = new int[][]{{-1, -1, -1}, {0,  0,  0}, {1,  1,  1}};

// sobel operator
public final static int[][] SOBEL_X = new int[][]{{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
public final static int[][] SOBEL_Y = new int[][]{{-1, -2, -1}, {0,  0,  0}, {1,  2,  1}};

// direction parameter
public final static int X_DIRECTION = 0;
public final static int Y_DIRECTION = 2;
public final static int XY_DIRECTION = 4;
private int direction;
private boolean isSobel;

direction = XY_DIRECTION;
isSobel = true;
}

public void setSoble(boolean sobel) {
this.isSobel = sobel;
}

public int getDirection() {
return direction;
}

public void setDirection(int direction) {
this.direction = direction;
}

@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;
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 = -1; subrow <= 1; subrow++) {
for(int subcol = -1; subcol <= 1; 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;

if(isSobel) {
xred += (SOBEL_X[subrow + 1][subcol + 1] * tr);
xgreen +=(SOBEL_X[subrow + 1][subcol + 1] * tg);
xblue +=(SOBEL_X[subrow + 1][subcol + 1] * tb);

yred += (SOBEL_Y[subrow + 1][subcol + 1] * tr);
ygreen +=(SOBEL_Y[subrow + 1][subcol + 1] * tg);
yblue +=(SOBEL_Y[subrow + 1][subcol + 1] * tb);
} else {
xred += (PREWITT_X[subrow + 1][subcol + 1] * tr);
xgreen +=(PREWITT_X[subrow + 1][subcol + 1] * tg);
xblue +=(PREWITT_X[subrow + 1][subcol + 1] * tb);

yred += (PREWITT_Y[subrow + 1][subcol + 1] * tr);
ygreen +=(PREWITT_Y[subrow + 1][subcol + 1] * tg);
yblue +=(PREWITT_Y[subrow + 1][subcol + 1] * tb);
}
}
}

double mred = Math.sqrt(xred * xred + yred * yred);
double mgreen = Math.sqrt(xgreen * xgreen + ygreen * ygreen);
double mblue = Math.sqrt(xblue * xblue + yblue * yblue);
if(XY_DIRECTION == direction)
{
outPixels[index] = (ta << 24) | (clamp((int)mred) << 16) | (clamp((int)mgreen) << 8) | clamp((int)mblue);
}
else if(X_DIRECTION == direction)
{
outPixels[index] = (ta << 24) | (clamp((int)yred) << 16) | (clamp((int)ygreen) << 8) | clamp((int)yblue);
}
else if(Y_DIRECTION == direction)
{
outPixels[index] = (ta << 24) | (clamp((int)xred) << 16) | (clamp((int)xgreen) << 8) | clamp((int)xblue);
}
else
{
// as default, always XY gradient
outPixels[index] = (ta << 24) | (clamp((int)mred) << 16) | (clamp((int)mgreen) << 8) | clamp((int)mblue);
}

// cleanup for next loop
newRow = newCol = 0;
xred = xgreen = xblue = 0;
yred = ygreen = yblue = 0;

}
}
setRGB(dest, 0, 0, width, height, outPixels );
return dest;
}

public static int clamp(int value) {
return value < 0 ? 0 : (value > 255 ? 255 : value);
}

}


## 数字图像处理--图像梯度算子的本质

2019-04-03 11:29:55 baidu_38172402 阅读数 2136
• ###### 图像梯度

掌握OpenCV核心模块，熟练使用相关API 理解各个API背后的相关算法原理，每个参数意义 有能力解决使用应用场景问题，大量工程代码经验分享 掌握图像处理与视频分析，图像分析与测量编码与开发技巧

98人学习 贾志刚
免费试看

gx = z8 - z5
gy = z6 - z5

z9-z5算不算灰度值的变化？z1-z5呢？z7-z5呢？z4-z5呢？z3-z5呢？

gx = z9-z5
gy = z8-z6

gx = (z7+z8+z9)-(z1+z2+z3)
gy = (z3+z6+z9)-(z1+z4+z7)

gx = (z7+2*z8+z9)-(z1+2*z2+z3)
gy = (z3+2*z6+z9)-(z1+2*z4+z7)


import cv2
import numpy as np

row, column = moon.shape
moon_f = np.copy(moon)
moon_f = moon_f.astype("float")

Roberts = np.zeros((row, column))

for x in range(row - 1):
for y in range(column - 1):
gx = abs(moon_f[x + 1, y + 1] - moon_f[x, y])
gy = abs(moon_f[x + 1, y] - moon_f[x, y + 1])
Roberts[x, y] = gx + gy

sharp = moon_f + Roberts
sharp = np.where(sharp < 0, 0, np.where(sharp > 255, 255, sharp))
sharp = sharp.astype("uint8")

cv2.imshow("moon", moon)
cv2.imshow("Roberts_sharp", sharp)
cv2.waitKey()123456789101112131415161718192021222324

再看看用上面自定义算子的情况：
user_defined = np.zeros((row, column))

for x in range(1, row - 1):
for y in range(1, column - 1):
gx = abs((moon_f[x + 1, y - 1] + moon_f[x + 1, y] + moon_f[x + 1, y + 1]) - (
moon_f[x - 1, y - 1] + moon_f[x - 1, y] + moon_f[x - 1, y + 1]))
gy = abs((moon_f[x - 1, y + 1] + moon_f[x, y + 1] + moon_f[x + 1, y + 1]) - (
moon_f[x - 1, y - 1] + moon_f[x, y - 1] + moon_f[x + 1, y - 1]))

user_defined[x, y] = gx + gy

sharp = moon_f + user_defined
sharp = np.where(sharp < 0, 0, np.where(sharp > 255, 255, sharp))
sharp = sharp.astype("uint8")

cv2.imshow("moon", moon)
cv2.imshow("defined_sharp", sharp)
cv2.waitKey()
1234567891011121314151617181920

## MATLAB梯度算子处理图像

2018-11-20 17:17:43 dyq1995 阅读数 5349
• ###### 图像梯度

掌握OpenCV核心模块，熟练使用相关API 理解各个API背后的相关算法原理，每个参数意义 有能力解决使用应用场景问题，大量工程代码经验分享 掌握图像处理与视频分析，图像分析与测量编码与开发技巧

98人学习 贾志刚
免费试看

下面简要介绍一下不同的梯度算子对于图像处理的区别：

1、首先打开MATLAB软件，在主界面的编辑器中写入下列代码：

subplot(3,2,1);
imshow(I);
title('原始图像');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I1=im2bw(I);
subplot(3,2,2);
imshow(I1);
title('二值图像');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I2=edge(I1,'roberts');
figure;
subplot(3,2,3);
imshow(I2);
title('roberts算子分割结果');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I3=edge(I1,'sobel');
subplot(3,2,4);
imshow(I3);
title('sobel算子分割结果');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I4=edge(I1,'Prewitt');
subplot(3,2,5);
imshow(I4);
title('Prewitt算子分割结果 ');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系

2、命名保存好之后，点击运行按钮，出现如下所示结果：

## OpenCV-Python实践之图像梯度算子

2019-04-06 19:11:31 Small_Munich 阅读数 493
• ###### 图像梯度

掌握OpenCV核心模块，熟练使用相关API 理解各个API背后的相关算法原理，每个参数意义 有能力解决使用应用场景问题，大量工程代码经验分享 掌握图像处理与视频分析，图像分析与测量编码与开发技巧

98人学习 贾志刚
免费试看
##### 图像梯度算子简介

相信只要是懂些图像处理的知识，都知道图像梯度的含义。不知道是否考虑过为什么图像梯度如此广泛认知与使用？为什么不使用图像纹理、图像色彩、图像相位等等，在这里我并不是说上述除了图像梯度之外，其它的图像信息不重要，我只是想说图像梯度最为广泛的被研究与使用。下面我们来看一幅图像：

从上图坐标为灰度图像，右边为Laplacian算子提取的图像梯度图；现在我们来看一下左边图片中的A、B、C、D、E、F区域，你可以通过这些子区域发现处于图像中的哪个位置吗？通过人眼观察可以轻易得出结果：E、F最容易分辨，C、D能够确定更小的范围区域，A、B最难分辨在哪个范围。OK，让我们来看右边的梯度算子，可以发现：E、F小区域在梯度图像上较为完整的保留下来，C、D保留边缘曲线，A、B已经完全发现不出什么明显的特征。

通过上述一个简单的观察，你会发现：E、F是角点区域(梯度各个方向变化最为明显)，C、D为边缘区域(梯度垂直于边缘方向最为明显)、A、B为平坦区域(梯度各个方向变化都不明显)。这不就是后面做特征点检测的信息丰富度准则，角点最为稳定、边缘检测等特征。图像梯度提取最为简单直接，能够有效的描述图像的原始状态，因此发展一系列的图像梯度算子：Roberts、Prewitt、Sobel、Laplacian、Scharr等。下面介绍一下比较经常使用的梯度提取算子卷积核函数：

Sobel算子：

$W_{sobelx}= \left[ \begin{matrix} w_{00} & w_{01} & w_{02} \\ w_{10} & w_{11} & w_{12} \\ w_{20} & w_{21} & w_{22} \end{matrix} \right] = \left[ \begin{matrix} -1 & 0 & +1 \\ -2 & 0 & +2 \\ -1 & 0 & +1 \end{matrix} \right]$

$W_{sobely}= \left[ \begin{matrix} w_{00} & w_{01} & w_{02} \\ w_{10} & w_{11} & w_{12} \\ w_{20} & w_{21} & w_{22} \end{matrix} \right] = \left[ \begin{matrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ +1 & +2 & +1 \end{matrix} \right]$

$G_{image}=\sqrt{G^{2}_x+G^{2}_y}\tag{1}$

参数解释：$G_{image}$为Sobel算子提取的梯度图像，$G_x$$W_{sobelx}$卷积核与原始图像卷积提取X方向的结果，$G_y$$W_{sobely}$卷积核与原始图像卷积提取$Y$方向的结果。

Scharr算子：

$W_{scharrx}= \left[ \begin{matrix} w_{00} & w_{01} & w_{02} \\ w_{10} & w_{11} & w_{12} \\ w_{20} & w_{21} & w_{22} \end{matrix} \right] = \left[ \begin{matrix} -3 & 0 & +3 \\ -10 & 0 & +10 \\ -3 & 0 & +3 \end{matrix} \right]$

$W_{scharry}= \left[ \begin{matrix} w_{00} & w_{01} & w_{02} \\ w_{10} & w_{11} & w_{12} \\ w_{20} & w_{21} & w_{22} \end{matrix} \right] = \left[ \begin{matrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ +3 & +10 & +3 \end{matrix} \right]$

Scharr算子与Sobel算子原理一致，只是改进版，效果要比Sobel好些。

Laplacian算子：

拉普拉斯算子是最广为人知的算子，完全的尺度不变性，依赖二阶导数能够提取稳定的特征点，著名的差分高斯近似加速等等。其提取图像特征的核函数为：

$W_{laplacian}= \left[ \begin{matrix} w_{00} & w_{01} & w_{02} \\ w_{10} & w_{11} & w_{12} \\ w_{20} & w_{21} & w_{22} \end{matrix} \right] = \left[ \begin{matrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{matrix} \right]$

利用卷积核与图像进行卷积运算，以此来提取图像梯度。关于卷积操作具体解释可以参考图像滤波算法系列实战总结之一博文开头卷积示例图片，抱歉暂无找到引用何处，发现后会添加上。

##### OpenCV-Python代码实践
import cv2
import numpy as np
from matplotlib import pyplot as plt

laplacian = cv2.Laplacian(img, cv2.CV_64F)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)

sobelxy = np.sqrt(sobelx*sobelx + sobely*sobely)

scharrx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=-1)
scharry = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=-1)

scharrxy = np.sqrt(scharrx*scharrx + scharry*scharry)

plt.subplot(2, 4, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 2), plt.imshow(laplacian, cmap='gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 3), plt.imshow(sobelx, cmap='gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 4), plt.imshow(sobely, cmap='gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 5), plt.imshow(scharrx, cmap='gray')
plt.title('Scharr X'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 6), plt.imshow(scharry, cmap='gray')
plt.title('Scharr Y'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 7), plt.imshow(sobelxy, cmap='gray')
plt.title('Sobel XY'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 8), plt.imshow(scharrxy, cmap='gray')
plt.title('Scharr XY'), plt.xticks([]), plt.yticks([])

plt.show()


## [转]图像梯度：算子

2017-09-01 15:51:53 firstlai 阅读数 10443
• ###### 图像梯度

掌握OpenCV核心模块，熟练使用相关API 理解各个API背后的相关算法原理，每个参数意义 有能力解决使用应用场景问题，大量工程代码经验分享 掌握图像处理与视频分析，图像分析与测量编码与开发技巧

98人学习 贾志刚
免费试看

## 1 推导

### 1.1 Robert算子

推导过程。（因为平方和平方根需要大量的计算开销，所以使用绝对值来近似梯度幅值

### 1.2 Prewitt算子

其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的，这两个方向模板一个检测水平边缘，一个检测垂直边缘。

### 1.3 Sobel算子

Sobel算子和Prewitt算子都是加权平均，但是Sobel算子认为，邻域的像素对当前像素产生的影响不是等价的，所以距离不同的像素具有不同的权值，对算子结果产生的影响也不同。一般来说，距离越远，产生的影响越小。同样，也分为垂直方向和水平方向两个。

### 1.4 Isotropic Sobel算子

加权平均算子，权值反比于邻点与中心点的距离，当沿不同方向检测边缘时梯度幅度一致，就是通常所说的各向同性。

### 1.5 Laplace算子

二阶微分算子，具有各向同向性，与坐标轴无关（所以无法检测方向）。但是对噪声敏感，所以图像一般需要经过平滑处理，因为平滑处理也是基于模板的，所以通常是使用Laplace算子和平滑算子结合起生成新的模板。

 0 1 0 1 -4 1 0 1 0

 1 1 1 1 -8 1 1 1 1

## 2 代码

Robert 算子在X和Y方向，分别对无噪声和有噪声的处理后的效果。可以很明显看出噪声影响较大。

Prewwit算子效果如下。

Sobel算子如下。

拉普拉斯算子如下。

## 3 参考

http://blog.csdn.net/xiaojiegege123456/article/details/7714863

http://www.cnblogs.com/german-iris/p/4840647.html