edgefirst-image 0.38.1

High-performance image processing with hardware acceleration for edge AI
Documentation
#version 300 es
precision highp float;
precision highp int;
uniform highp sampler2D src;
uniform ivec2 img_size;
// Reciprocal of the R8 texture's size: (row stride in bytes, rows).
uniform vec2 inv_tex;
// Inclusive texel bounds (x0, y0, x1, y1) of the source crop: every tap is
// clamped to them, so a crop never reads pixels from outside itself.
uniform ivec4 src_rect;
in vec3 fragPos;
in vec2 tc;
out vec4 color;

vec3 src_px(int x, int y) {
    float b = float(x * 3) + 0.5;
    float v = (float(y) + 0.5) * inv_tex.y;
    return vec3(texture(src, vec2(b * inv_tex.x, v)).r,
                texture(src, vec2((b + 1.0) * inv_tex.x, v)).r,
                texture(src, vec2((b + 2.0) * inv_tex.x, v)).r);
}

// Under LINEAR filtering, at texture row coordinate `v`. Each tap sits 1/1024
// texel right of its byte's centre so the horizontal weight quantizes to zero:
// a tap computed exactly at the centre can land a hair left of it and blend
// in a fraction of the previous byte, which belongs to another channel.
vec3 src_col(int x, float v) {
    float b = float(x * 3) + 0.5 + 1.0 / 1024.0;
    return vec3(texture(src, vec2(b * inv_tex.x, v)).r,
                texture(src, vec2((b + 1.0) * inv_tex.x, v)).r,
                texture(src, vec2((b + 2.0) * inv_tex.x, v)).r);
}

void main() {
    ivec2 i = clamp(ivec2(tc * vec2(img_size)), src_rect.xy, src_rect.zw);
    vec3 rgb = src_px(i.x, i.y);
    color = vec4(rgb, 1.0);
}