早前研究神经网络时有了解过卷积,但是没有形成思维模型,渐渐遗忘了。最近又开始研究卷积在图形学中的应用,或许因为更形象吧,发现卷积变得好理解了。
其实最主要的还是看到了这张图。
可以这么理解,有A、B两个矩阵(这儿只研究卷积在图形学中的应用,故不考虑其他维度),从A中选取一个元素a0,然后根据B的尺寸,提取出a0周围一圈的元素,构成了一个子矩阵A0,A0与B的尺寸要一致。然后让A0与B的元素一一对应并相乘后求和,最后的值就是a0的卷积。就像一圈数卷住了a0,又被盖了层被子,最后裹挟在一起变成一个新的数。
在图形学中,B可以称为卷积算子,图片A可以被B卷积计算后变成一张新的图。用不同的卷积算子,最后生成的图也各不相同。
今天研究的不多,就只放了一个浮雕的效果。
代码:
Shader "MyShader/SS_13_0" { Properties { _MainTex ("Texture", 2D) = "white" {} _Detail ("Detail", 2D) = "white" {} _Delta("Delta",float)=0.01//进行UV卷积计算的dlta } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; sampler2D _Detail; float4 _MainTex_ST; float4 _Detail_ST; fixed _Delta; int _Size;//算子的尺寸 float _Operator1[256];//算子。本来应该根据_Size的尺寸来声明数组的长度,但是没找到动态改变的方法,所以就声明大一点 float _Operator2[256]; float2 _Offest[256];// 偏移量。根据偏移量获取与矩阵一一对应的UV struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float2 uv1 : TEXCOORD01; }; struct v2f { float2 uv : TEXCOORD0; float2 uv1 : TEXCOORD1; float4 vertex : SV_POSITION; }; fixed4 convolution(float2 _uv){ fixed4 _col=fixed4(0,0,0,0); for(int i=0;i<_Size;i++){ for(int j=0;j<_Size;j++){ fixed2 _uv0=_uv+_Offest[i*j]*_Delta;//根据下标获取矩阵对应的位置 fixed4 _col0=tex2D(_Detail, _uv0);//获取该位置的色值 _col0*=_Operator1[i*j]*_Operator2[i*j]; _col+= _col0;//对应色值累加,获得最后的卷积 } } return _col; } v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.uv1= TRANSFORM_TEX(v.uv1, _Detail); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 temp=convolution(i.uv1); return temp+tex2D(_MainTex, i.uv); } ENDCG } } } using System.Collections; using System.Collections.Generic; using UnityEngine; //[ExecuteInEditMode] public class SS_13_0 : MonoBehaviour { public int Size = 3; Vector4[] Offest; float[] Operator1; float[] Operator2; Material mat;//注意将图片设置为Clamp private void Start() { Init(); } [ContextMenu("Init")] void Init() { Offest = new Vector4[Size * Size]; for (var i = 0; i < Size; i++) { for(var j = 0; j < Size; j++) { Offest[i*j] = new Vector4(i-Size / 2,j- Size / 2,0,0); } } //Operator1 = new float[] { // 0.1f,0.1f,0.1f, // 0.1f,0.2f,0.1f,//此处用的是一个中央增强的效果,也能用其他算子 // 0.1f,0.1f,0.1f //}; Operator1 = new float[] { -0.1f,0.0f,1.0f, -2f,1.0f,2f,//浮雕算子1 -1f,0.0f,1f }; Operator2 = new float[] { -1f,-2f,-1f, 0,1,0,//浮雕算子2 1f,2f,1f }; mat = gameObject.GetComponent<MeshRenderer>().material; mat.SetFloat("_Size", Size); mat.SetFloatArray("_Operator1", Operator1); mat.SetFloatArray("_Operator2", Operator2); mat.SetVectorArray("_Offest", Offest); } }这篇算是初解,之后深入研究后再写一篇卍解。
返回目录:https://blog.csdn.net/yzy1987523/article/details/106676451