如何在 webgl 直方图中对像素进行排序并实现 linearGradient?
How to sort pixels and implement linearGradient in webgl histogram?
我正在尝试使用 webgl 为图像实现直方图。
我能够在 javascript HTML5 Canvas 中通过获取 255 长度的数组并通过 0-255 增加每个索引的像素值并使用 createLinearGradient 创建直方图来做到这一点。
for(var c = 0; c < 256; c++){
histogram[c] = 0;
}
var ctx = document.getElementById('canvas').getContext('2d');
var pixels= ctx.getImageData(0, 0, width, height).data;
for (var i = 0, j = 0; i < u8a.length; i++, j = j + 4) {
histogram[pixels[j]]++; //increasing pixel index for histogram
}
为了在 WebGL 中实现相同的功能,我指的是这个 jsfiddle 但我看到的是直方图不平滑且未排序。
所以,我在使用 WebGL 时遇到了两件事:
-上述fiddle中0.0(0)到1.0(255)的像素值如何排序?
-如何在webgl with/without线性渐变中使直方图平滑?
代码:
precision mediump float;
uniform sampler2D u_histTexture;
uniform vec2 u_resolution;
uniform sampler2D u_maxTexture;
void main() {
// get the max color constants
vec4 maxColor = texture2D(u_maxTexture, vec2(0));
// compute our current UV position
vec2 uv = gl_FragCoord.xy / u_resolution;
// Get the history for this color
// (note: since u_histTexture is 256x1 uv.y is irrelevant
vec4 hist = texture2D(u_histTexture, uv);
// scale by maxColor so scaled goes from 0 to 1 with 1 = maxColor
vec4 scaled = hist / maxColor;
// 1 > maxColor, 0 otherwise
vec4 color = step(uv.yyyy, scaled);
float rr = 0.2989 * color.r + 0.5870 * color.g + 0.1140 * color.b;
gl_FragColor = vec4(rr, rr, rr, 1);
}
我能解决的最好的问题是你不想排序,而是想做一个黑白直方图(所有通道 r、g、b 合并)。
要做到这一点,您只需要对所有通道求和的一次传递,而不是像目前那样需要 4 次传递。
您需要更改以下着色器并替换 javascript 中的一些渲染调用。
将"hist-vs"改为
attribute float pixelId;
uniform vec2 u_resolution;
uniform sampler2D u_texture;
void main() {
vec2 pixel = vec2(mod(pixelId, u_resolution.x), floor(pixelId / u_resolution.x));
vec2 uv = (pixel + 0.5) / u_resolution;
vec4 color = texture2D(u_texture, uv);
float colorSum = (color.r + color.g + color.b) / 3.0 ;
gl_Position = vec4((colorSum * 255.0 + 0.5) / 256.0 * 2.0 - 1.0, 0.5, 0, 1);
gl_PointSize = 1.0;
}
将"max-vs"改为
precision mediump float;
uniform sampler2D u_texture;
void main() {
vec4 maxColor = vec4(0);
for (int i = 0; i < 256; i++) {
vec2 uv = vec2((float(i) + 0.5) / 256.0, 0.5);
maxColor = max(maxColor, vec4(texture2D(u_texture, uv).rgb, 1));
}
gl_FragColor = maxColor;
}
将"show-fs"改为
precision mediump float;
uniform sampler2D u_histTexture;
uniform vec2 u_resolution;
uniform sampler2D u_maxTexture;
void main() {
vec3 maxColor = texture2D(u_maxTexture, vec2(0)).rgb;
vec2 uv = gl_FragCoord.xy / u_resolution;
vec3 hist = texture2D(u_histTexture, uv).rgb;
gl_FragColor = vec4(step(uv.yyy, hist / maxColor) * uv.x, 1);
}
更改为 javascript
然后在 Javascript 中,您只需调用一次,而不是调用第一个着色器 4 次。此外,由于不需要蒙版制服,因此您无需将其传递给着色器。
原来的for循环
for (var channel = 0; channel < 4; ++channel) {
gl.colorMask(channel === 0, channel === 1, channel === 2, channel === 3);
twgl.setUniforms(histProgramInfo, {
u_texture: tex,
u_colorMult: [
channel === 0 ? 1 : 0,
channel === 1 ? 1 : 0,
channel === 2 ? 1 : 0,
channel === 3 ? 1 : 0,
],
u_resolution: [img.width, img.height],
});
twgl.drawBufferInfo(gl, gl.POINTS, pixelIdBufferInfo);
}
将所有这些行替换为
gl.colorMask(true, true, true, false);
twgl.setUniforms(histProgramInfo, { u_texture: tex, u_resolution: [img.width, img.height]});
twgl.drawBufferInfo(gl, gl.POINTS, pixelIdBufferInfo);
我正在尝试使用 webgl 为图像实现直方图。 我能够在 javascript HTML5 Canvas 中通过获取 255 长度的数组并通过 0-255 增加每个索引的像素值并使用 createLinearGradient 创建直方图来做到这一点。
for(var c = 0; c < 256; c++){
histogram[c] = 0;
}
var ctx = document.getElementById('canvas').getContext('2d');
var pixels= ctx.getImageData(0, 0, width, height).data;
for (var i = 0, j = 0; i < u8a.length; i++, j = j + 4) {
histogram[pixels[j]]++; //increasing pixel index for histogram
}
为了在 WebGL 中实现相同的功能,我指的是这个 jsfiddle 但我看到的是直方图不平滑且未排序。
所以,我在使用 WebGL 时遇到了两件事:
-上述fiddle中0.0(0)到1.0(255)的像素值如何排序?
-如何在webgl with/without线性渐变中使直方图平滑?
代码:
precision mediump float;
uniform sampler2D u_histTexture;
uniform vec2 u_resolution;
uniform sampler2D u_maxTexture;
void main() {
// get the max color constants
vec4 maxColor = texture2D(u_maxTexture, vec2(0));
// compute our current UV position
vec2 uv = gl_FragCoord.xy / u_resolution;
// Get the history for this color
// (note: since u_histTexture is 256x1 uv.y is irrelevant
vec4 hist = texture2D(u_histTexture, uv);
// scale by maxColor so scaled goes from 0 to 1 with 1 = maxColor
vec4 scaled = hist / maxColor;
// 1 > maxColor, 0 otherwise
vec4 color = step(uv.yyyy, scaled);
float rr = 0.2989 * color.r + 0.5870 * color.g + 0.1140 * color.b;
gl_FragColor = vec4(rr, rr, rr, 1);
}
我能解决的最好的问题是你不想排序,而是想做一个黑白直方图(所有通道 r、g、b 合并)。
要做到这一点,您只需要对所有通道求和的一次传递,而不是像目前那样需要 4 次传递。
您需要更改以下着色器并替换 javascript 中的一些渲染调用。
将"hist-vs"改为
attribute float pixelId;
uniform vec2 u_resolution;
uniform sampler2D u_texture;
void main() {
vec2 pixel = vec2(mod(pixelId, u_resolution.x), floor(pixelId / u_resolution.x));
vec2 uv = (pixel + 0.5) / u_resolution;
vec4 color = texture2D(u_texture, uv);
float colorSum = (color.r + color.g + color.b) / 3.0 ;
gl_Position = vec4((colorSum * 255.0 + 0.5) / 256.0 * 2.0 - 1.0, 0.5, 0, 1);
gl_PointSize = 1.0;
}
将"max-vs"改为
precision mediump float;
uniform sampler2D u_texture;
void main() {
vec4 maxColor = vec4(0);
for (int i = 0; i < 256; i++) {
vec2 uv = vec2((float(i) + 0.5) / 256.0, 0.5);
maxColor = max(maxColor, vec4(texture2D(u_texture, uv).rgb, 1));
}
gl_FragColor = maxColor;
}
将"show-fs"改为
precision mediump float;
uniform sampler2D u_histTexture;
uniform vec2 u_resolution;
uniform sampler2D u_maxTexture;
void main() {
vec3 maxColor = texture2D(u_maxTexture, vec2(0)).rgb;
vec2 uv = gl_FragCoord.xy / u_resolution;
vec3 hist = texture2D(u_histTexture, uv).rgb;
gl_FragColor = vec4(step(uv.yyy, hist / maxColor) * uv.x, 1);
}
更改为 javascript
然后在 Javascript 中,您只需调用一次,而不是调用第一个着色器 4 次。此外,由于不需要蒙版制服,因此您无需将其传递给着色器。
原来的for循环
for (var channel = 0; channel < 4; ++channel) {
gl.colorMask(channel === 0, channel === 1, channel === 2, channel === 3);
twgl.setUniforms(histProgramInfo, {
u_texture: tex,
u_colorMult: [
channel === 0 ? 1 : 0,
channel === 1 ? 1 : 0,
channel === 2 ? 1 : 0,
channel === 3 ? 1 : 0,
],
u_resolution: [img.width, img.height],
});
twgl.drawBufferInfo(gl, gl.POINTS, pixelIdBufferInfo);
}
将所有这些行替换为
gl.colorMask(true, true, true, false);
twgl.setUniforms(histProgramInfo, { u_texture: tex, u_resolution: [img.width, img.height]});
twgl.drawBufferInfo(gl, gl.POINTS, pixelIdBufferInfo);