【发布时间】:2019-11-20 00:16:58
【问题描述】:
我想在 GLSL 中实现一个称为模式过滤器的图像过滤器,以便在 WebGL 应用程序中使用。模式过滤器从周围像素计算模式(最频繁)值,如果有一个最频繁的值,则将像素颜色设置为模式,否则保持不变。周围像素由内核大小决定,通常为以相关像素为中心的 9 或 25 个像素。
我是着色器、GLSL 以及实现性能的复杂性的真正初学者,我目前的实现似乎特别糟糕。我正在寻求帮助以找到更有效的方法。
我将当前的着色器放入 https://www.shadertoy.com/view/wsVSWw 的着色器玩具中,我的速度低于 10 fps!请注意,您需要为 iChannel0 选择一些内容才能看到效果。
编辑
我将计数排序算法转换为 GLSL 并从中值滤波器中抓取一个循环,结果现在是 30fps,新版本在https://www.shadertoy.com/view/tsVSDm
在我的特殊情况下,我正在处理一张灰度照片,所以我只关心红色通道。
这是为 webgl 实现的着色器,它与 shadertoy 版本有细微差别(例如 texture2D() 而不是 texture()):
precision mediump float;
varying vec2 v_coord;
uniform sampler2D u_texture;
uniform vec2 imageResolution;
int histogram[256];
void main() {
vec2 pos = vec2(v_coord.x, 1.0 - v_coord.y);
vec4 outColor = texture2D(u_texture, pos);
gl_FragColor = outColor;
/* the mode filter does not apply to semi-transparent pixels
for performance reasons, we would need to mix pixels based
on alpha to get the effective color for the mode calculation
then remix to get the correct color with the current pixel's
alpha. This is both hairy and would add processing time
*/
if (outColor.a < 1.0) {
return;
}
vec2 onePixel = vec2(1) / imageResolution;
for (int i = 0; i<256; i++) {
histogram[i] = 0;
}
int maxValue = 0;
int offset = int(float(${kernelSize})/2.0);
for (int yy = 0; yy < ${kernelSize}; yy ++) {
for (int xx = 0; xx < ${kernelSize}; xx ++) {
vec2 samplePos = pos + vec2(yy - offset, xx - offset) * onePixel;
vec4 color = texture2D(u_texture, samplePos);
if (color.a == 1.0) {
int red = int(color.r * 255.0);
for (int i = 0; i<256; i++) {
if (i == red) {
histogram[i]++;
maxValue = int(max(float(maxValue), float(histogram[i])));
}
}
}
}
}
/* the number of values that have the maximum mode value */
int numModes = 0;
/* the colour (index) of the maximum node value */
int modeValue = 0;
for (int i = 0; i<256; i++) {
if (histogram[i] == maxValue) {
numModes++;
modeValue = i;
}
}
if (numModes == 1) {
outColor.r = float(modeValue) / 255.0;
}
outColor.g = outColor.r;
outColor.b = outColor.r;
gl_FragColor = outColor;
}
【问题讨论】: