Unity之梯度应用实现Roberts、Prewitt、Sobel边缘检测
2017-12-26 10:26
661 查看
通常使用Roberts、Prewitt、Sobel算子计算梯度,在图像处理时,梯度值比较常见的应用是用来计算边缘检测。
其原理是通过算子,计算出图像每一个像素的梯度值,再通过判断梯度值的大小,来判定该像素是不是边缘像素。判定方式有很多种,可以直接用梯度作为权,用来在正常颜色和边缘颜色之间插值。也可以设定一个阙值,梯度值大于该阙值时,认为是边缘像素。
关于算子的计算原理,其实就是一个小型的矩阵,有3 x 3的,也有 9 x 9的等等,在遍历图像上的每一个像素时,按照该矩阵,选取出该像素周围的像素点,用来计算该像素与周围像素之间的关系。
对于梯度,每个算子都有两个分量,分别用来计算X方向和Y方向的梯度。对于X方向,一般都是从左到右,所以变化不大。但是对于Y方向,有些平台是从下往上(坐标原点在左下角),有些平台是从上往下(坐标原点在左上角)。我们需要根据实际情况翻转Y方向的梯度算子。
这里看一下百度百科中对 Sobel算子 的描述:
可以看到同样的Y方向梯度算子,前后描述并不一致,上下颠倒。这是因为在上面的描述中,遍历算子中像素的方式和下面不一样。当我们需要从左往右,从上往下遍历算子时,就应采用第一个公式。
我们在遍历算子时使用从左往右,从下往上的顺序,应采用第二个公式。
下面两个图片表示了3x3算子的两种不同的遍历顺序:
在本例中,我们采用的是,红色示例表示的遍历的顺序。
接下来给出本例中使用的算子:
Roberts算子
Gx
Gy
Prewitt算子
Gx
Gy
Sobel
Gx
Gy
接下来给出代码:
使用步骤:
将该脚本挂在场景中的摄像机上,并在场景中设置一张图片,使相机可以拍摄到该图片。
并且需要新建一张RanderTexture挂在相机的TargetTexture 上面。
GradType 参数可以选择不同的算子。
调整相应的参数后,在编辑器模式下右键点击该组件,执行RanderTexture方法,就可以在asset/TextureOutput目录下生成一张处理后的图片。
这里特别邀请皮卡叔做一下模特:
放几张张最终的结果对比图(EdgeColor黑色,BackColor白色,EdgeWight = 1)。
Sobel算子。
Prewitt算子:
Roberts算子:
其原理是通过算子,计算出图像每一个像素的梯度值,再通过判断梯度值的大小,来判定该像素是不是边缘像素。判定方式有很多种,可以直接用梯度作为权,用来在正常颜色和边缘颜色之间插值。也可以设定一个阙值,梯度值大于该阙值时,认为是边缘像素。
关于算子的计算原理,其实就是一个小型的矩阵,有3 x 3的,也有 9 x 9的等等,在遍历图像上的每一个像素时,按照该矩阵,选取出该像素周围的像素点,用来计算该像素与周围像素之间的关系。
对于梯度,每个算子都有两个分量,分别用来计算X方向和Y方向的梯度。对于X方向,一般都是从左到右,所以变化不大。但是对于Y方向,有些平台是从下往上(坐标原点在左下角),有些平台是从上往下(坐标原点在左上角)。我们需要根据实际情况翻转Y方向的梯度算子。
这里看一下百度百科中对 Sobel算子 的描述:
可以看到同样的Y方向梯度算子,前后描述并不一致,上下颠倒。这是因为在上面的描述中,遍历算子中像素的方式和下面不一样。当我们需要从左往右,从上往下遍历算子时,就应采用第一个公式。
我们在遍历算子时使用从左往右,从下往上的顺序,应采用第二个公式。
下面两个图片表示了3x3算子的两种不同的遍历顺序:
在本例中,我们采用的是,红色示例表示的遍历的顺序。
接下来给出本例中使用的算子:
Roberts算子
Gx
Gy
Prewitt算子
Gx
Gy
Sobel
Gx
Gy
接下来给出代码:
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.IO; [ExecuteInEditMode] public class Gradient : MonoBehaviour { public Color edgeColor = Color.black; public Color backColor = Color.white; //边缘颜色比重 [Range(< 4000 span class="hljs-number">0f,1f)] public float edgeWeight = 0.3f; //梯度算子类型 public GradientType gradType; //算子权值 private int[] weighArrX; private int[] weighArrY; //Roberts遍历方向 private int[][] dir1 = { new int[2] { 0, 0 }, new int[2] { 1, 0 }, new int[2] { 0, 1 }, new int[2] { 1, 1 }, }; //Prewitt、Sobel遍历方向 private int[][] dir2 = { new int[2] { -1, -1 }, new int[2] { 0, -1 }, new int[2] { 1, -1}, new int[2] { -1, 0 }, new int[2] { 0, 0}, new int[2] { 1, 0}, new int[2] { -1, 1}, new int[2] { 0, 1 }, new int[2] { 1, 1 }, }; //遍历方向 private int[][] dir; public void GetAllGradient(Texture2D tex) { if (!tex) { Debug.LogError("tex is null !!!"); return; } Color[] colors = new Color[tex.width * tex.height]; //初始化数据 InitData(); int cnt = 0; //遍历图片,计算各个像素的梯度值 for (int i = 0; i < tex.height; i++) { for (int j = 0; j < tex.width; j++) { //遍历算子 float Lumin = 0f; float gradX = 0f; float gradY = 0f; for (int k = 0; k < dir.Length; k++) { int idx1 = i + dir[k][0]; int idx2 = j + dir[k][1]; // if ((idx1 >= 0 && idx1 <= tex.width) && (idx2 >= 0 && idx2 <= tex.height)) { Lumin = GetLuminance(tex.GetPixel(idx1, idx2)); gradX += Lumin * weighArrX[k]; gradY += Lumin * weighArrY[k]; } } //梯度值 float grad = Mathf.Abs(gradX) + Mathf.Abs(gradY); Color pixelColor = GetPixelColor(grad, tex.GetPixel(i, j)); colors[cnt] = pixelColor; cnt++; } } tex.SetPixels(colors); } //初始化数据 void InitData() { switch (gradType) { case GradientType.Roberts: weighArrX = new int[4] { -1, 0, 0, 1 }; weighArrY = new int[4] { 0, -1, 1, 0 }; dir = dir1; break; case GradientType.Prewitt: weighArrX = new int[9] { -1, 0, 1, -1, 0, 1, -1, 0, 1 }; weighArrY = new int[9] { -1, -1, -1, 0, 0, 0, 1, 1, 1 }; dir = dir2; break; case GradientType.Sobel: weighArrX = new int[9] { -1, 0, 1, -2, 0, 2, -1, 0, 1 }; weighArrY = new int[9] { -1, -2, -1 , 0, 0, 0, 1, 2, 1 }; dir = dir2; break; default: break; } } //获得亮度值 private float GetLuminance(Color _color) { return 0.2125f * _color.r + 0.7154f * _color.g + 0.0721f * _color.b; } private Color GetPixelColor(float grad, Color _pixelColor) { Color c = new Color(); Color _edgeColor = Color.Lerp(_pixelColor, edgeColor, grad); Color _backColor = Color.Lerp(backColor, edgeColor, grad); c = Color.Lerp(_edgeColor, _backColor, edgeWeight); return c; } [ContextMenu("RenderTexture")] public void DoRenderTexture() { DrawTex(); } void DrawTex() { //获得相机 Camera catchCamera = GetComponent<Camera>(); //暂存当前渲染图像 RenderTexture rendText = RenderTexture.active; //改为相机图像 RenderTexture.active = catchCamera.targetTexture; catchCamera.Render(); Texture2D camTex = new Texture2D(catchCamera.targetTexture.width, catchCamera.targetTexture.height, TextureFormat.ARGB32, false); camTex.ReadPixels(new Rect(0, 0, catchCamera.targetTexture.width, catchCamera.targetTexture.height), 0, 0); camTex.Apply(); RenderTexture.active = rendText; //进行边缘检测 GetAllGradient(camTex); //保存图片 byte[] bytes = camTex.EncodeToPNG(); File.WriteAllBytes(Application.dataPath+ "/TextureOutput/" + System.DateTime.Now.ToFileTime() + ".png", bytes); } } public enum GradientType { Roberts, Prewitt, Sobel, }
使用步骤:
将该脚本挂在场景中的摄像机上,并在场景中设置一张图片,使相机可以拍摄到该图片。
并且需要新建一张RanderTexture挂在相机的TargetTexture 上面。
GradType 参数可以选择不同的算子。
调整相应的参数后,在编辑器模式下右键点击该组件,执行RanderTexture方法,就可以在asset/TextureOutput目录下生成一张处理后的图片。
这里特别邀请皮卡叔做一下模特:
放几张张最终的结果对比图(EdgeColor黑色,BackColor白色,EdgeWight = 1)。
Sobel算子。
Prewitt算子:
Roberts算子:
相关文章推荐
- [ZZ] 边缘检测 梯度与Roberts、Prewitt、Sobel、Lapacian算子
- 图像梯度特征的常用边缘检测算子:Sobel、Prewitt、Roberts
- 图像边缘检测与边缘增强处理——(Roberts、prewitt、sobel)
- 几种边缘检测算子的比较Roberts,Sobel,Prewitt,LOG,Canny
- OpenCV2马拉松第14圈——边缘检测(Sobel,prewitt,roberts)
- matlab边缘检测代码(包含roberts,sobel,prewitt三种算子)
- 使用roberts Prewitt Sobel 三种算子对raw格式图像进行边缘检测
- 13. 用Roberts、Sobel、Prewitt和Laplace算子对一幅灰度图像进行边缘检测。观察异同。
- 边缘检测类(包括Roberts, Sobel, Prewitt, Kirsch等算子的边缘检测算法) - wtuyzh的专栏 - CSDNBlog
- 第六节--基于Sobel的边缘检测C++程序的实现
- 图像sobel、laplacian、canny边缘检测算法基础实现
- 【cuda学习笔记】2.纹理对象API的使用,实现sobel边缘检测
- cuda实践之sobel边缘检测实现
- 图像处理中各种边缘检测的微分算子简单比较(Sobel,Robert, Prewitt,Laplacian,Canny)
- OpenCV2马拉松第14圈——边缘检測(Sobel,prewitt,roberts)
- [转载]边缘检测的各种微分算子比较(Sobel,Robert,Prewitt,Laplacian,Canny)
- 基于MATLAB的Sobel边缘检测算法实现
- opencv实现sobel边缘检测
- 图像处理中各种边缘检测的微分算子简单比较(Sobel,Robert, Prewitt,Laplacian,Canny)
- 图像处理中各种边缘检测的微分算子简单比较(Sobel,Robert, Prewitt,Laplacian,Canny)