shader入门精要读书笔记38 边缘检测(使用深度、法线纹理)

一、前言

因为之前使用的边缘检测,通过屏幕后处理效果使用Sobel算子进行边缘检测的,这种很有可能会导致我们不需要的一些东西(比如阴影、纹理等等)

所以我们尽可能使用在深度纹理和法线纹理上进行边缘检测,这些纹理检测不会受光照和纹理影响,仅仅保存了当前物体的模型信息,这样边缘检测就更加可靠。在三维空间中可以更好地得到应用。

二、实现

摄像机代码(具体解释见代码注释):

using UnityEngine;
using System.Collections;

public class EdgeDetectNormalsAndDepth : PostEffectsBase {

	public Shader edgeDetectShader;
	private Material edgeDetectMaterial = null;
	public Material material {  
		get {
			edgeDetectMaterial = CheckShaderAndCreateMaterial(edgeDetectShader, edgeDetectMaterial);
			return edgeDetectMaterial;
		}  
	}

	[Range(0.0f, 1.0f)]
	public float edgesOnly = 0.0f;          //边缘线强度	为0时边缘会叠加在原渲染图像上,为1只显示边缘

	public Color edgeColor = Color.black;		//线的颜色

	public Color backgroundColor = Color.white;		//背景颜色

	public float sampleDistance = 1.0f;			//控制深度+法线纹理采样时,使用的采样距离。

	public float sensitivityDepth = 1.0f;			//影响邻域的深度值相差多少认为存在边界

	public float sensitivityNormals = 1.0f;			//影响邻域的法线值相差多少认为存在边界

	void OnEnable() {
		GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;		//同时得到深度和法线纹理
	}

	[ImageEffectOpaque]         //通常OnRenderImage会在所有物体渲染后调用,这里我们使用命令,使其不对透明物体产生影响
	void OnRenderImage (RenderTexture src, RenderTexture dest) {
		if (material != null) {
			material.SetFloat("_EdgeOnly", edgesOnly);			//传递就完事了
			material.SetColor("_EdgeColor", edgeColor);
			material.SetColor("_BackgroundColor", backgroundColor);
			material.SetFloat("_SampleDistance", sampleDistance);
			material.SetVector("_Sensitivity", new Vector4(sensitivityNormals, sensitivityDepth, 0.0f, 0.0f));

			Graphics.Blit(src, dest, material);
		} else {
			Graphics.Blit(src, dest);
		}
	}
}

Shader脚本代码:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unity Shaders Book/Chapter 13/Edge Detection Normals And Depth" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_EdgeOnly ("Edge Only", Float) = 1.0		//边缘线强度	为0时边缘会叠加在原渲染图像上,为1只显示边缘
		_EdgeColor ("Edge Color", Color) = (0, 0, 0, 1)
		_BackgroundColor ("Background Color", Color) = (1, 1, 1, 1)
		_SampleDistance ("Sample Distance", Float) = 1.0
		_Sensitivity ("Sensitivity", Vector) = (1, 1, 1, 1)		//x、y分量分别对应法线和深度的检测灵敏度
	}
	SubShader {
		CGINCLUDE
		
		#include "UnityCG.cginc"
		
		sampler2D _MainTex;
		half4 _MainTex_TexelSize;
		fixed _EdgeOnly;
		fixed4 _EdgeColor;
		fixed4 _BackgroundColor;
		float _SampleDistance;
		half4 _Sensitivity;
		
		sampler2D _CameraDepthNormalsTexture;			//获取深度和法线纹理
		
		struct v2f {
			float4 pos : SV_POSITION;
			half2 uv[5]: TEXCOORD0;		//定义数组为5的纹理坐标数组
		};
		  
		v2f vert(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			
			half2 uv = v.texcoord;		//纹理坐标
			o.uv[0] = uv;
			
			#if UNITY_UV_STARTS_AT_TOP		//深度纹理采样坐标差异化处理
			if (_MainTex_TexelSize.y < 0)
				uv.y = 1 - uv.y;
			#endif
			
			o.uv[1] = uv + _MainTex_TexelSize.xy * half2(1,1) * _SampleDistance;		//存储我们需要采样的另外4个纹理坐标
			o.uv[2] = uv + _MainTex_TexelSize.xy * half2(-1,-1) * _SampleDistance;		
			o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1,1) * _SampleDistance;
			o.uv[4] = uv + _MainTex_TexelSize.xy * half2(1,-1) * _SampleDistance;
					 
			return o;
		}
		
		half CheckSame(half4 center, half4 sample) {

			//分别提取两个采样结果得到法线和深度(这里并没有解码得到真的法线值,因为我们只需比较差异)
			half2 centerNormal = center.xy;						
			float centerDepth = DecodeFloatRG(center.zw);
			half2 sampleNormal = sample.xy;
			float sampleDepth = DecodeFloatRG(sample.zw);
			
			// difference in normals
			// do not bother decoding normals - there's no need here
			half2 diffNormal = abs(centerNormal - sampleNormal) * _Sensitivity.x;		//差异再绝对值,乘以灵敏度
			int isSameNormal = (diffNormal.x + diffNormal.y) < 0.1;			//把差异值的每个分量相加再和阙值比较
			// difference in depth
			float diffDepth = abs(centerDepth - sampleDepth) * _Sensitivity.y;			//同样
			// scale the required threshold by the distance
			int isSameDepth = diffDepth < 0.1 * centerDepth;					//这里意思大概为检测深度值差异是否影响很大
			
			// return:
			// 1 - if normals and depth are similar enough
			// 0 - otherwise
			return isSameNormal * isSameDepth ? 1.0 : 0.0;		//只要有一个不满足就为0
		}
		
		fixed4 fragRobertsCrossDepthAndNormal(v2f i) : SV_Target {
			half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.uv[1]);		//对4个纹理坐标进行深度+法线采样
			half4 sample2 = tex2D(_CameraDepthNormalsTexture, i.uv[2]);		
			half4 sample3 = tex2D(_CameraDepthNormalsTexture, i.uv[3]);
			half4 sample4 = tex2D(_CameraDepthNormalsTexture, i.uv[4]);
			
			half edge = 1.0;
			
			edge *= CheckSame(sample1, sample2);			//这里可以看出我们对比的是对角相邻纹理坐标
			edge *= CheckSame(sample3, sample4);
			
			fixed4 withEdgeColor = lerp(_EdgeColor, tex2D(_MainTex, i.uv[0]), edge);
			//使用edge在自己本来的颜色和边缘线之间插值,edge越小withEdgeColor颜色越靠近边缘线颜色
			fixed4 onlyEdgeColor = lerp(_EdgeColor, _BackgroundColor, edge);
			//使用edge在边缘线颜色和背景颜色间插值,
			
			return lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly);
			//_EdgeOnly插值上面两个颜色。
			//实现当_EdgeOnly为0时 显示的是 图像颜色和边缘线的混合
			//当_EdgeOnly为1时 显示的是 边缘线和背景颜色的混合(没有图像本身了),
		}
		
		ENDCG
		
		Pass { 
			ZTest Always Cull Off ZWrite Off
			
			CGPROGRAM      
			
			#pragma vertex vert  
			#pragma fragment fragRobertsCrossDepthAndNormal
			
			ENDCG  
		}
	} 
	FallBack Off
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深度边缘检测是指在使用Intel RealSense D435深度相机进行图像处理时,通过分析深度图像中的深度值差异来检测物体的边界。深度图像是由相机测量到的每个像素点与相机的距离值组成的。深度边缘检测可以通过比较相邻像素点的深度值来确定边界位置。 在进行深度边缘检测时,可以使用基于颜色的边缘检测方法,通过比较像素点的深度值差异来确定边界。这种方法的优点是只需要深度图像本身,无需额外信息。然而,如果两个物体的深度差异不明显,即使存在边界,也可能无法检测出来。因此,对于需要更准确的边缘效果,可以使用其他更确的边缘检测方法,如基于法线深度差异的方法。通过计算当前采样点周围像素点的法线深度差异,并设置阈值,可以确定边界位置。 深度边缘检测在计算机视觉中具有广泛的应用,例如图像分割、对象检测和视频对象分割。然而,由于复杂的背景和不一致的注释等因素,深度边缘检测是一个具有挑战性的问题。因此,在实际应用中,需要根据具体情况选择适合的边缘检测方法和参数设置,以获得准确的边界和视觉上显著的边缘。 #### 引用[.reference_title] - *1* [Unity Shader-边缘检测效果(基于颜色,基于深度法线边缘流光效果,转场效果)](https://blog.csdn.net/puppet_master/article/details/83759180)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [深度学习之边缘检测算法论文解读(EDTER: Edge Detection with Transformer)](https://blog.csdn.net/qq_41627642/article/details/128568272)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [深度学习传统CV算法——边缘检测算法综述](https://blog.csdn.net/weixin_42917352/article/details/121977458)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值