边缘检测的原理就是利用一些边缘检测算子对图像进行卷积操作。卷积操作就是使用一个卷积核对一张图像中的每个像素进行一系列的操作。如果相邻像素之间存在差别明显的颜色、亮度、纹理等属性,我们就会认为它们之间有一条边界。这种相邻像素之间的差值可以用梯度(gradient)表示,边缘处的梯度绝对值会比较大。3种常见的边缘检测算子如下图所示

每个边缘算子都包含了两个方向的卷积核,分别用于检测水平方向和竖直方向上的边缘信息。进行边缘检测时,我们需要对每个像素分别进行一次卷积计算,得到两个方向上的梯度值Gx和Gy,整体梯度按下面公式计算:G=√(Gx*Gx + Gy * Gy)。出于性能考虑,可以用绝对值代替开根号操作G= |Gx| + |Gy|。算法如下Sobel函数(其中计算纹理坐标的代码可以从片元着色器转移到顶点着色器,提高性能,因为从顶点着色器到片元着色器的插值是线性的。):
//计算该像素对应的亮度值
inline fixed luminance(fixed4 color)
{
return 0.2125 *color.r + 0.7154 * color.g + 0.0721 * color.b;
}
//计算梯度值
inline half Sobel(half2 uv_mainTex,half2 mainTexSize)
{
const half Gy[9] = {-1, -2 , -1,
0,0, 0,
1,2, 1};
const half Gx[9]= {-1, 0 , 1,
-2,0, 2,
-1,0, 1};
half texColor;
half edgeX = 0;
half edgeY = 0;
half mod = 0;
for(int it = 0;it < 9; it++){
mod =fmod(it, 3);
half2 uv = uv_mainTex+ mainTexSize * half2((mod - 1), ((it - mod) / 3 - 1));
texColor =luminance(tex2D(_MainTex,uv));
edgeX +=texColor * Gx[it];
edgeY +=texColor * Gy[it];
}
half edge = 1 -abs(edgeX) - abs(edgeY);
return edge;
}
网友评论