UnityShader-屏幕后處理之邊緣檢測

一锥债、屏幕后處理原理

我的另外一篇文章有詳細(xì)的介紹:
UnityShader-屏幕后處理(調(diào)節(jié)亮度陡蝇,飽和度,對比度)

二赞弥、卷積與卷積核

卷積核通常是一個(gè)四方形網(wǎng)格結(jié)構(gòu)(例如2x2毅整,3x3的方形區(qū)域),該方形區(qū)域每個(gè)方格都有一個(gè)權(quán)重值绽左。當(dāng)對圖像中的某個(gè)像素進(jìn)行卷積時(shí)悼嫉,我們會(huì)把卷積核的中心位置放在該像素上,翻轉(zhuǎn)核之后再依次計(jì)算核中每個(gè)元素和其覆蓋的圖形像素值的乘積并求和拼窥,得到的結(jié)果就是該位置的像素值戏蔑。
卷積操作指的是使用一個(gè)卷積核對圖像中的每個(gè)像素進(jìn)行一系列的操作。


卷積核.png

三鲁纠、邊緣檢測原理

(1)怎么確定形成了一條邊呢总棵?

如果相鄰的像素之間存在差別明顯的顏色、亮度改含、紋理等屬性情龄,我們就會(huì)認(rèn)為他們之間應(yīng)該是有一條邊界的,這種相鄰像素之間的差值可以用梯度來表示。

(2)常見的的幾種邊緣檢測的算子
常見的邊緣檢測算子.png

在本例子中骤视,我們使用Sobel算子鞍爱。

(3)梯度計(jì)算公式

通常包括兩個(gè)方向的卷積核,一個(gè)是水平方向专酗,一個(gè)是豎直方向睹逃,我們需要對每個(gè)像素進(jìn)行一個(gè)卷積計(jì)算,得到兩個(gè)方向的梯度值Gx和Gy祷肯。整體公式:

出于性能考慮沉填,用絕對值代替開根號(hào):
(4)代碼實(shí)現(xiàn)

C#代碼:

using UnityEngine;
using System.Collections;

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);
        }
    }
}

shader代碼:

Shader "Unity Shaders Book/Chapter 12/Edge Detection" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _EdgeOnly ("Edge Only", Float) = 1.0
        _EdgeColor ("Edge Color", Color) = (0, 0, 0, 1)
        _BackgroundColor ("Background Color", Color) = (1, 1, 1, 1)
    }
    SubShader {
        Pass {  
            //設(shè)置渲染狀態(tài)
            ZTest Always Cull Off ZWrite Off
            
            CGPROGRAM
            
            #include "UnityCG.cginc"
            
            #pragma vertex vert  
            #pragma fragment fragSobel
            
            sampler2D _MainTex;
            //_MainTex_TexelSize:xxx_TexelSize是unity為我們提供的訪問xxx紋理對應(yīng)每個(gè)紋素大小的變量。
            //例如佑笋,一張512x512大小的紋理翼闹,該值大約為0.001953的(即1/512)
            uniform half4 _MainTex_TexelSize;
            fixed _EdgeOnly;
            fixed4 _EdgeColor;
            fixed4 _BackgroundColor;
            
            struct v2f {
                float4 pos : SV_POSITION;
                half2 uv[9] : TEXCOORD0;
            };
              
            v2f vert(appdata_img v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                
                half2 uv = v.texcoord;
                //通過_MainTex_TexelSize.xy值,計(jì)算需要計(jì)算的矩陣的UV值
                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);
                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;
            }
            //計(jì)算亮度值
            fixed luminance(fixed4 color) {
                return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; 
            }
            
            //通過Sobe算子算出這個(gè)像素點(diǎn)與周圍的梯度值
            half Sobel(v2f i) {
                //Sobe算子矩陣允青,分為X與Y兩個(gè)方向
                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;
                //累加周圍采樣點(diǎn)的梯度值
                for (int it = 0; it < 9; it++) {
                    texColor = luminance(tex2D(_MainTex, i.uv[it]));
                    edgeX += texColor * Gx[it];
                    edgeY += texColor * Gy[it];
                }
                //用絕對值代替開根號(hào)
                half edge = 1 - abs(edgeX) - abs(edgeY);
                
                return edge;
            }
            
            fixed4 fragSobel(v2f i) : SV_Target {
                half edge = Sobel(i);
                //根據(jù)梯度值橄碾,將原顏色與背景顏色卵沉、描邊顏色進(jìn)行插值運(yùn)算颠锉,得到最終的顏色值
                fixed4 withEdgeColor = lerp(_EdgeColor, tex2D(_MainTex, i.uv[4]), edge);
                fixed4 onlyEdgeColor = lerp(_EdgeColor, _BackgroundColor, edge);
                return lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly);
            }
            
            ENDCG
        } 
    }
    FallBack Off
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市史汗,隨后出現(xiàn)的幾起案子琼掠,更是在濱河造成了極大的恐慌,老刑警劉巖停撞,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓷蛙,死亡現(xiàn)場離奇詭異,居然都是意外死亡戈毒,警方通過查閱死者的電腦和手機(jī)艰猬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埋市,“玉大人冠桃,你說我怎么就攤上這事〉勒” “怎么了食听?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長污茵。 經(jīng)常有香客問我樱报,道長,這世上最難降的妖魔是什么泞当? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任迹蛤,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盗飒。我一直安慰自己穷缤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布箩兽。 她就那樣靜靜地躺著津肛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汗贫。 梳的紋絲不亂的頭發(fā)上身坐,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音落包,去河邊找鬼部蛇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛咐蝇,可吹牛的內(nèi)容都是我干的涯鲁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼有序,長吁一口氣:“原來是場噩夢啊……” “哼抹腿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起旭寿,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤警绩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后盅称,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肩祥,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年缩膝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了混狠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疾层,死狀恐怖将饺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情云芦,我是刑警寧澤俯逾,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站舅逸,受9級(jí)特大地震影響桌肴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜琉历,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一坠七、第九天 我趴在偏房一處隱蔽的房頂上張望水醋。 院中可真熱鬧,春花似錦彪置、人聲如沸拄踪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惶桐。三九已至,卻和暖如春潘懊,著一層夾襖步出監(jiān)牢的瞬間姚糊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國打工授舟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留救恨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓释树,卻偏偏與公主長得像肠槽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子奢啥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 不同圖像灰度不同秸仙,邊界處一般會(huì)有明顯的邊緣,利用此特征可以分割圖像扫尺。需要說明的是:邊緣和物體間的邊界并不等同筋栋,邊緣...
    大川無敵閱讀 13,848評(píng)論 0 29
  • 知乎上看到一個(gè)話題——目前火熱的 Deep Learning 會(huì)滅絕傳統(tǒng)的 SIFT / SURF 特征提取方法嗎...
    牛奶芝麻閱讀 100,829評(píng)論 4 81
  • 這篇文章總結(jié)比較全面:http://blog.csdn.net/timidsmile/article/detail...
    rogerwu1228閱讀 1,827評(píng)論 0 3
  • 目前比較火熱的圖像識(shí)別技術(shù),如車牌號(hào)識(shí)別正驻、身份證識(shí)別、人臉識(shí)別等抢腐,都廣泛運(yùn)用到了圖像邊緣檢測姑曙,今天我所介紹的就是O...
    航行在藍(lán)天的螞蚱閱讀 5,183評(píng)論 0 2
  • 你的筆記只有一種顏色嗎? 你的筆記布滿了密密麻麻的小字嗎迈倍? 你是一字一句記下老師或分享者的所有內(nèi)容嗎伤靠? 你會(huì)重新大...
    空箋閱讀 281評(píng)論 0 2