Sobel Filter是一个相当简单的边缘查找算法,他能检测比较锐利的边缘(模糊的图片或不锐利的边缘无法有效检测,请搜索Canny Filter算法)
方法是获得当前点以及周围点的权重来描述当前点位置上的边缘强度(颜色变化速度)
-
横向边缘检测Mx
-
紫色像素的周围九宫格与横向检测矩阵dot得到一个值,这个值的大小就是边缘颜色变化率,当两侧颜色相同或相近时,你可以看到这个值趋近于0. 整体图视作Gx
-
同样方法可以检测纵向的颜色变化,这样可以得到一张图片的两个不同方向的灰度变化图Gx和Gy
-
如何混合两个不同方向上的边缘强度变化?
答案是两个方向的平方和开方
强度为G = (Gx*Gx+Gy*Gy)^0.5;
方向为R = atan(Gy/Gx);
godot shader实现
- 这里只用到了强度
- 因为gdshader的内建函数还不能在自定义函数中直接调用,暂时使用传参方法
shader_type canvas_item;
vec3 samplef(vec2 offset, vec2 uv, sampler2D text, vec2 tsize){
return texture(text, vec2(uv+offset*tsize)).rgb;
}
float luminance(vec3 c){
return dot(c,vec3(.2126,.7152,.0722));
// return dot(c,vec3(1.))*0.3333;
}
vec3 sobelFilter(vec2 uv, sampler2D text, vec2 tsize){
//
vec3 hc=samplef(vec2(-1.,-1.),uv,text,tsize)+samplef(vec2(0.,-1.),uv,text,tsize)*2.
+samplef(vec2(1.,-1.),uv,text,tsize)+samplef(vec2(-1.,1.),uv,text,tsize)*-1.
+samplef(vec2(0.,1.),uv,text,tsize)*-2.+samplef(vec2(1.,1.),uv,text,tsize)*-1.;
//
vec3 vc=samplef(vec2(-1.,-1.),uv,text,tsize)+samplef(vec2(-1.,0.),uv,text,tsize)*2.
+samplef(vec2(-1.,1.),uv,text,tsize)+samplef(vec2(1.,-1.),uv,text,tsize)*-1.
+samplef(vec2(1.,0.),uv,text,tsize)*-2.+samplef(vec2(1.,1.),uv,text,tsize)*-1.;
return texture(text,uv).rgb*pow(luminance(vc*vc+hc*hc),.6);
}
void fragment(){
// COLOR = vec4(sobelFilter(UV, TEXTURE, TEXTURE_PIXEL_SIZE),1.0);
// COLOR = vec4(vec3(length(sobelFilter(UV,TEXTURE,TEXTURE_PIXEL_SIZE))),1.);
COLOR = vec4(vec3(length(sobelFilter(UV,TEXTURE,TEXTURE_PIXEL_SIZE))),texture(TEXTURE,UV).a);
}
原图 | 结果 |
---|---|
视频:
https://www.bilibili.com/video/av15346632?from=search&seid=17167334084508443686