我一直在尝试使用GPU从图片生成颜色直方图(实际上是实时相机预览),因此opengl-es
。我遇到了包含histogram filter的GPUImage
库。我无法直接使用此库,因为我正在使用react-native
与Expo GLView
(记录为here),我不想处理本机代码。
这就是说,我应该能够调整代码以使用由WebGL API
管理的GLView
。我一直试图这样做,但检索到的直方图数据只包含“黑色像素”。
定义着色器:
const histogramRedSamplingVertexShaderSource = `#version 300 es
precision mediump float;
in vec4 position;
out vec3 colorFactor;
void main()
{
colorFactor = vec3(1.0, 0.0, 0.0);
gl_Position = vec4(-1.0 + (position.x * 0.0078125), 0.0, 0.0, 1.0);
gl_PointSize = 1.0;
}
`;
const histogramGreenSamplingVertexShaderSource = `#version 300 es
precision mediump float;
in vec4 position;
out vec3 colorFactor;
void main()
{
colorFactor = vec3(0.0, 1.0, 0.0);
gl_Position = vec4(-1.0 + (position.y * 0.0078125), 0.0, 0.0, 1.0);
gl_PointSize = 1.0;
}
`;
const histogramBlueSamplingVertexShaderSource = `#version 300 es
precision mediump float;
in vec4 position;
out vec3 colorFactor;
void main()
{
colorFactor = vec3(0.0, 0.0, 1.0);
gl_Position = vec4(-1.0 + (position.z * 0.0078125), 0.0, 0.0, 1.0);
gl_PointSize = 1.0;
}
`;
const histogramAccumulationFragmentShaderSource = `#version 300 es
precision mediump float;
in lowp vec3 colorFactor;
out vec4 fragColor;
const lowp float scalingFactor = 1.0 / 256.0;
void main()
{
fragColor = vec4(colorFactor * scalingFactor, 1.0);
}`;
助手功能(供参考)
createShader = (gl, type, source) => {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
};
createProgram = (gl, vertexShader, fragmentShader) => {
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.validateProgram(program);
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
};
初始化
// width and height of the camera view.
const { width, height } = this.state;
const downsamplingFactor = 16;
const cameraTexture = (this.texture = await this.createCameraTexture());
gl.bindTexture(gl.TEXTURE_2D, cameraTexture);
const cameraFramebuffer = gl.createFramebuffer();
const histogramFramebuffer = gl.createFramebuffer();
const histogramAccumulationFragmentShader = this.createShader(gl, gl.FRAGMENT_SHADER, histogramAccumulationFragmentShaderSource);
const histogramRedSamplingVertexShader = this.createShader(gl, gl.VERTEX_SHADER, histogramRedSamplingVertexShaderSource);
const histogramRedSamplingProgram = this.createProgram(gl, histogramRedSamplingVertexShader, histogramAccumulationFragmentShader);
const histogramGreenSamplingVertexShader = this.createShader(gl, gl.VERTEX_SHADER, histogramGreenSamplingVertexShaderSource);
const histogramGreenSamplingProgram = this.createProgram(gl, histogramGreenSamplingVertexShader, histogramAccumulationFragmentShader);
const histogramBlueSamplingVertexShader = this.createShader(gl, gl.VERTEX_SHADER, histogramBlueSamplingVertexShaderSource);
const histogramBlueSamplingProgram = this.createProgram(gl, histogramBlueSamplingVertexShader, histogramAccumulationFragmentShader);
渲染循环
// Binding camera texture to framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, cameraFramebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
cameraTexture,
0
);
// Reading pixel data from the camera image.
const pixelData = new Uint8Array(4 * width * height);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
console.log(pixelData[101]); // Logging one random pixel (yields value different from zero)
// Adapted from https://github.com/BradLarson/GPUImage2/blob/master/framework/Source/Operations/Histogram.swift
// releaseIncomingFramebuffers
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// activateFramebufferForRendering
gl.bindFramebuffer(gl.FRAMEBUFFER, histogramFramebuffer);
gl.viewport(0, 0, 256, 3);
// clearFramebufferWithColor
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// enableAdditiveBlending
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.ONE, gl.ONE);
gl.enable(gl.BLEND);
// histogramRedSamplingProgram
gl.useProgram(histogramRedSamplingProgram);
const histogramRedPositionAttributeLocation = gl.getAttribLocation(
histogramRedSamplingProgram,
'position'
);
gl.vertexAttribPointer(
histogramRedPositionAttributeLocation,
4,
gl.UNSIGNED_BYTE,
0,
(downsamplingFactor - 1) * 4,
pixelData
);
gl.drawArrays(gl.POINTS, 0, width * height / downsamplingFactor);
// histogramGreenSamplingProgram
gl.useProgram(histogramGreenSamplingProgram);
const histogramGreenPositionAttributeLocation = gl.getAttribLocation(
histogramGreenSamplingProgram,
'position'
);
gl.vertexAttribPointer(
histogramGreenPositionAttributeLocation,
4,
gl.UNSIGNED_BYTE,
0,
(downsamplingFactor - 1) * 4,
pixelData
);
gl.drawArrays(gl.POINTS, 0, width * height / downsamplingFactor);
// histogramBlueSamplingProgram
gl.useProgram(histogramBlueSamplingProgram);
const histogramBluePositionAttributeLocation = gl.getAttribLocation(
histogramBlueSamplingProgram,
'position'
);
gl.vertexAttribPointer(
histogramBluePositionAttributeLocation,
4,
gl.UNSIGNED_BYTE,
0,
(downsamplingFactor - 1) * 4,
pixelData
);
gl.drawArrays(gl.POINTS, 0, width * height / downsamplingFactor);
// disableBlending
gl.disable(gl.BLEND);
// End of transposition.
const histogramData = new Uint8Array(3 * 256 * 3);
gl.readPixels(0, 0, 256, 3, gl.RGB, gl.UNSIGNED_BYTE, histogramData);
// Try to read some pixel data, from the histogram 256x1 center line,
// these should be different from zero.
console.log([
histogramData[256 * 3 + 120],
histogramData[256 * 3 + 121],
histogramData[256 * 3 + 122],
]);
直方图数据仅包含零(而相机像素数据是有效/非零值)。有可能错误是在帧缓冲区周围;在“模型”中,framebuffer has a defined size,但我看不到如何转置它。 (错误也可能来自其他地方)。