通常,边缘检测归结为检测具有高梯度值的图像区域。
在我们的例子中,我们可以粗略地看到梯度作为衍生图像功能的,因此梯度的大小给你上的信息有多少图像局部改变(在相邻像素/纹理像素的问候)。
现在,正如您所说的,边缘是不连续的指示,因此,既然我们定义了渐变,就很清楚此信息就是我们所需要的。一旦找到图像的梯度,只需将阈值应用于图像即可获得二进制值的边缘/非边缘。
您如何找到这个梯度确实是您要问的,但我还没有回答:)
有很多方法!这里一对:)
内置着色器功能
hlsl和glsl都提供派生功能。在GLSL中,您可以使用dFdx和dFdy分别为您提供x和y方向上的渐变信息。通常,这些功能以2x2片段的块进行评估。
除非您对单个方向感兴趣,否则是一种紧凑结果的好方法,该结果表明区域中的梯度的宽度是fwidth,除dFdy和dFdy的绝对值之和外,其他什么都没有。
您可能会对整个图像的边缘感兴趣,而不是对特定通道感兴趣,因此您可能希望将图像功能转换为亮度。考虑到这一点,当涉及边缘检测时,着色器可能包含以下内容:
float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
float gradient = fwidth(luminance );
float isEdge = gradient > threshold;
高阈值时,您会发现较粗糙的边缘,相反,低阈值时,您可能会发现一些虚假边缘。您必须尝试找到最适合您需求的阈值。
这些功能起作用的原因值得一提,但我现在没有时间,我可能会在以后更新此答案:)
屏幕空间后处理
您可能会做得更好,现在图像处理中的边缘检测领域非常广阔。我可以根据您的需求引用数十种检测边缘检测的好方法,但是现在让我们保持简单,如果您有兴趣,我可以引用更多的选择!
因此,该想法与上面的想法类似,不同之处在于,您可以查看更广泛的邻域,并根据需要对加权样本使用一组权重。通常,您使用内核对图像进行卷积,从而为您提供良好的渐变信息。
一个非常常见的选择是Sobel内核
分别为您提供x和y方向的渐变:
ģ ř 一个d我Ë Ñ 吨中号一克Ñ 我Ť ù ðÈ = (g ^ - [R 一d我È Ñ 吨X)2+ (g ^ - [R 一d我È Ñ 吨ÿ)2-----------------------√
然后,您可以像我上面提到的一样阈值。
如您所见,该内核将更多的权重分配给中央像素,因此有效地计算了梯度+一点平滑度,这在传统上是有帮助的(通常对图像进行高斯模糊处理以消除小边缘)。
上面的方法工作得很好,但是如果您不喜欢平滑,则可以使用Prewitt内核:
(请注意,我很着急,很快就会写出正确格式的文本而不是图像!)
确实有更多的内核和技术可以以图像处理y的方式而不是实时图形来查找边缘检测,因此我排除了更多复杂的方法(双关语无意),因为使用dFdx / y函数可能就很好了。