Unity Shader-Edge Detection

Unity Shader Edge Detection



Az élérzékelés (angolul: Edge Detection) alapvető probléma a képfeldolgozásban és a számítógépes látásban. Az élfelismerés célja a digitális képek nyilvánvaló fényerő-változással rendelkező pontjainak azonosítása. A képattribútumok jelentős változásai általában fontos eseményeket és az attribútumok változását tükrözik. Ide tartoznak: (i) folytonosságok mélységben, (ii) folytonosságok a felszín tájolásában, (iii) az anyag tulajdonságainak változásai és (iv) a színvilágítás változásai. Az élfelismerés a képfeldolgozás és a számítógép-látás kutatási területe, különösen a funkció-felismerés területén.

elv

Az élfelismerés lényegében a képen keresztül történik konvolúció Ennek eredményeként a konvolúció fontos művelet a matematikai elemzésben. A fő különbség az Konverziós kernel Választás, konvolúciós művelet révén nem csak megtehetjük Éldetektáló , Meg is teheti Homályos képÉlesítse a képet És egyéb funkciók.



Az „elmosódott kép” utalhat erre a cikkemre



További stroke árnyékolók, kérjük, olvassa el ezt



Éldetektáló Konverziós kernel más néven Élfelismerő operátor
mint például: Roberts Cross operátor, Prewitt operátor, Sobel operátor, Canny operátor, iránytű operátor

Itt van egy példa a Sobel operátorra:

G x = [+ 1 0 - 1 + 2 0 - 2 + 1 0 - 1] ∗ AG y = [+ 1 2 + 1 0 0 0 - 1 - 2 - 1] ∗ A G_x = kezdődik {bmatrix} + 1 & 0 & -1 \\ + 2 & 0 & -2 \\ + 1 & 0 & -1 end {bmatrix} * A qquad G_y = begin {bmatrix} + 1 & 2 & + 1 \\ 0 & 0 & 0 \\ - 1 & -2 & -1 vége {bmatrix} * A



A {A}Képviseli az eredeti képet,G x G y-vel G_x és G_yA vízszintes és függőleges élek által érzékelt képeket ábrázolja,

Külön kiszámítható a fenti képlettel Vízszintes val vel Függőleges nak,-nek Színátmenet értéke , amiG x G y-vel G_x és G_y
Minél nagyobb a gradiens értéke, annál nyilvánvalóbb az él.

jegyzet:

  • A színátmenet kiszámítása előtt a képet szürkén kell színezni, hogy kiszámíthassuk a színátmenet értékét
  • A vízszintes színátmenet értéke a függőleges élvonalat, a függőleges színátmenet pedig a vízszintes élvonalat érzékeli.

A fenti az elmélet, néhány barát nagyon zavart lehet, adjunk példát az illusztrálásra:
kép kép kép
Ha a fenti kép két 3 * 3 pixeles blokk, véletlenszerűen kiválasztottuk a képen, és a vízszintes Sobel operátorral

Az első pixel blokk gradiens értéke:G x 1 = 186 ∗ 1 + 186 ∗ 2 + 186 ∗ 1 - 233 ∗ 1 - 233 ∗ 2 - 232 ∗ 1 = - 187 G_ {x1} = 186 * 1 + 186 * 2 + 186 * 1 - 233 * 1 - 233 * 2- 232 * 1 = -187
A 2. pixel blokk gradiens értéke:G x 2 = 186 ∗ 1 + 186 ∗ 2 + 186 ∗ 1 - 185 ∗ 1 - 186 ∗ 2 - 186 ∗ 1 = 1 G_ {x2} = 186 * 1 + 186 * 2 + 186 * 1 - 185 * 1- 186 * 2- 186 * 1 = 1

Végül felvesszük abszolút értéküket, 187, illetve 1. Itt jól látható a különbség közöttük. Minél nagyobb a gradiens értéke, annál valószínűbb, hogy a pixel egy él!

Árnyékoló kód megvalósítása:

Először is szürkíteni kell a képet, a szürkítés nagyon egyszerű, a szürkeárnyalatos pszichológiai képlet révén Gray = R*0.299 + G*0.587 + B*0.114 Csak konvertálj!

Itt vízszintes és függőleges élfelismerést végzünk, hogy összehasonlíthassuk és megértsük.

Hozzon létre egy C # szkriptet, és húzza a kamerába:
PS: A PostEffectsBase alaposztály megtekinthető ebben a cikkemben

using UnityEngine using System.Collections //-----------------------------【Edge Detection】--------------- -------------- public class EdgeDetection : 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 public Color edgeColor = Color.black public Color backgroundColor = Color.white void OnRenderImage (RenderTexture src, RenderTexture dest) { if (material != null) { material.SetFloat('_EdgeOnly', edgesOnly) material.SetColor('_EdgeColor', edgeColor) material.SetColor('_BackgroundColor', backgroundColor) Graphics.Blit(src, dest, material) } else { Graphics.Blit(src, dest) } } }

árnyékoló: (vízszintes érzékelés)

//-----------------------------【Edge Detection】--------------- -------------- Shader 'lcl/learnShader3/002 Chapter 12/Edge Detection Test' { //-----------------------------【Attributes】---------------- ------------- Properties { _MainTex ('Base (RGB)', 2D) = 'white' {} } //-----------------------------【Sub Shader】-------------- --------------- SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #include 'UnityCG.cginc' #pragma vertex vert #pragma fragment frag sampler2D _MainTex uniform half4 _MainTex_TexelSize struct v2f { float4 pos : SV_POSITION half2 uv[9] : TEXCOORD0 } //-----------------------------【Vertex Shader】-------------- --------------- v2f vert(appdata_img v) { v2f o o.pos = UnityObjectToClipPos(v.vertex) half2 uv = v.texcoord //Calculate the texture coordinate position of surrounding pixels, where 4 is the original point, o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1, -1) o.uv[1] = uv + _MainTex_TexelSize.xy * half2(0, -1) o.uv[2] = uv + _MainTex_TexelSize.xy * half2(1, -1) o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1, 0) o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0, 0) //origin o.uv[5] = uv + _MainTex_TexelSize.xy * half2(1, 0) o.uv[6] = uv + _MainTex_TexelSize.xy * half2(-1, 1) o.uv[7] = uv + _MainTex_TexelSize.xy * half2(0, 1) o.uv[8] = uv + _MainTex_TexelSize.xy * half2(1, 1) return o } // Convert to grayscale fixed luminance(fixed4 color) { return 0.299 * color.r + 0.587 * color.g + 0.114 * color.b } // sobel operator half Sobel(v2f i) { const half Gx[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1} // const half Gy[9] = {-1, -2, -1, // 0, 0, 0, // 1, 2, 1} half texColor half edgeX = 0 half edgeY = 0 for (int it = 0 it < 9 it++) { // Convert to gray value texColor = luminance(tex2D(_MainTex, i.uv[it])) edgeX += texColor * Gx[it] // edgeY += texColor * Gy[it] } // half edge = 1 - abs(edgeX) - abs(edgeY) half edge = abs(edgeX) return edge } //-----------------------------【Fragment Shader】------------ ---------------- fixed4 frag(v2f i) : SV_Target { half edge = Sobel(i) return edge } ENDCG } } FallBack Off }

Végeredmény-összehasonlítás
kép
Végül egyesítjük a vízszintes és függőleges éleket és az eredeti képet. A végső élérzékelési eredmény:

kép
Az utolsó Shader-kód:

//-----------------------------【Edge Detection】--------------- -------------- Shader 'lcl/learnShader3/002 Chapter 12/Edge Detection Test' { //-----------------------------【Attributes】---------------- ------------- Properties { _MainTex ('Base (RGB)', 2D) = 'white' {} // Stroke level _EdgeOnly ('Edge Only', Float) = 1.0 // edge color _EdgeColor ('Edge Color', Color) = (0, 0, 0, 1) } //-----------------------------【Sub Shader】-------------- --------------- SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #include 'UnityCG.cginc' #pragma vertex vert #pragma fragment frag sampler2D _MainTex uniform half4 _MainTex_TexelSize fixed _EdgeOnly fixed4 _EdgeColor struct v2f { float4 pos : SV_POSITION half2 uv[9] : TEXCOORD0 } //-----------------------------【Vertex Shader】-------------- --------------- v2f vert(appdata_img v) { v2f o o.pos = UnityObjectToClipPos(v.vertex) half2 uv = v.texcoord //Calculate the texture coordinate position of surrounding pixels, where 4 is the original point, o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1, -1) o.uv[1] = uv + _MainTex_TexelSize.xy * half2(0, -1) o.uv[2] = uv + _MainTex_TexelSize.xy * half2(1, -1) o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1, 0) o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0, 0) //origin o.uv[5] = uv + _MainTex_TexelSize.xy * half2(1, 0) o.uv[6] = uv + _MainTex_TexelSize.xy * half2(-1, 1) o.uv[7] = uv + _MainTex_TexelSize.xy * half2(0, 1) o.uv[8] = uv + _MainTex_TexelSize.xy * half2(1, 1) return o } // Convert to grayscale fixed luminance(fixed4 color) { return 0.299 * color.r + 0.587 * color.g + 0.114 * color.b } // sobel operator half Sobel(v2f i) { const half Gx[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1} const half Gy[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1} half texColor half edgeX = 0 half edgeY = 0 for (int it = 0 it < 9 it++) { // Convert to gray value texColor = luminance(tex2D(_MainTex, i.uv[it])) edgeX += texColor * Gx[it] edgeY += texColor * Gy[it] } // merge horizontal and vertical half edge = 1 - (abs(edgeX) + abs(edgeY)) return edge } //-----------------------------【Fragment Shader】------------ ---------------- fixed4 frag(v2f i) : SV_Target { half edge = Sobel(i) fixed4 edgeColor = lerp(_EdgeColor, tex2D(_MainTex, i.uv[4]), edge) edgeColor = lerp(tex2D(_MainTex, i.uv[4]),edgeColor, _EdgeOnly) return edgeColor } ENDCG } } FallBack Off }