OpenGL Texture C++ Camera Filter滤镜

       基于OpenGL Texture纹理的强大功能,在片段着色器(Shader)中编写GLSL代码,对YUV的数据进行数据转换从而实现视频编辑软件中的相机滤镜功能。

        接上一篇OpenGL Texture C++ 预览Camera视频的功能实现,本篇来实现Camera滤镜效果并各种滤镜的切换。

        项目github地址:GitHub - wangyongyao1989/WyFFmpeg: 音视频相关基础实现

       效果展示:

         

filter_switch_show1

一.着色器程序创建及切换:

        着色器的编译/链接/使用基于上一篇OpenGL Texture C++ 预览Camera视频的OpenGLTextureVideoRender类进行createProgram() -> createTextures() -> draw() -> render()扩展应用,代码如下:

//  Author : wangyongyao https://github.com/wangyongyao1989
// Created by MMM on 2024/9/5.
//#include "OpenglesTexureVideoRender.h"
#include "OpenGLShader.h"void
OpenglesTexureVideoRender::init(ANativeWindow *window, AAssetManager *assetManager, size_t width,size_t height) {LOGI("OpenglesTexureVideoRender init==%d, %d", width, width);m_backingWidth = width;m_backingHeight = height;
}void OpenglesTexureVideoRender::render() {
//    LOGI("OpenglesTexureVideoRender render");glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);if (!updateTextures() || !useProgram()) return;glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}void OpenglesTexureVideoRender::updateFrame(const video_frame &frame) {m_sizeY = frame.width * frame.height;m_sizeU = frame.width * frame.height / 4;m_sizeV = frame.width * frame.height / 4;if (m_pDataY == nullptr || m_width != frame.width || m_height != frame.height) {m_pDataY = std::make_unique<uint8_t[]>(m_sizeY + m_sizeU + m_sizeV);m_pDataU = m_pDataY.get() + m_sizeY;m_pDataV = m_pDataU + m_sizeU;isProgramChanged = true;}m_width = frame.width;m_height = frame.height;if (m_width == frame.stride_y) {memcpy(m_pDataY.get(), frame.y, m_sizeY);} else {uint8_t *pSrcY = frame.y;uint8_t *pDstY = m_pDataY.get();for (int h = 0; h < m_height; h++) {memcpy(pDstY, pSrcY, m_width);pSrcY += frame.stride_y;pDstY += m_width;}}if (m_width / 2 == frame.stride_uv) {memcpy(m_pDataU, frame.u, m_sizeU);memcpy(m_pDataV, frame.v, m_sizeV);} else {uint8_t *pSrcU = frame.u;uint8_t *pSrcV = frame.v;uint8_t *pDstU = m_pDataU;uint8_t *pDstV = m_pDataV;for (int h = 0; h < m_height / 2; h++) {memcpy(pDstU, pSrcU, m_width / 2);memcpy(pDstV, pSrcV, m_width / 2);pDstU += m_width / 2;pDstV += m_width / 2;pSrcU += frame.stride_uv;pSrcV += frame.stride_uv;}}isDirty = true;
}void OpenglesTexureVideoRender::draw(uint8_t *buffer, size_t length, size_t width, size_t height,float rotation) {m_length = length;m_rotation = rotation;video_frame frame{};frame.width = width;frame.height = height;frame.stride_y = width;frame.stride_uv = width / 2;frame.y = buffer;frame.u = buffer + width * height;frame.v = buffer + width * height * 5 / 4;updateFrame(frame);
}void OpenglesTexureVideoRender::setParameters(uint32_t params) {m_params = params;
}uint32_t OpenglesTexureVideoRender::getParameters() {return m_params;
}bool OpenglesTexureVideoRender::createTextures() {auto widthY = (GLsizei) m_width;auto heightY = (GLsizei) m_height;glActiveTexture(GL_TEXTURE0);glGenTextures(1, &m_textureIdY);glBindTexture(GL_TEXTURE_2D, m_textureIdY);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthY, heightY, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,nullptr);if (!m_textureIdY) {LOGE("OpenGL Error Create Y texture");return false;}GLsizei widthU = (GLsizei) m_width / 2;GLsizei heightU = (GLsizei) m_height / 2;glActiveTexture(GL_TEXTURE1);glGenTextures(1, &m_textureIdU);glBindTexture(GL_TEXTURE_2D, m_textureIdU);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthU, heightU, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,nullptr);if (!m_textureIdU) {LOGE("OpenGL Error Create U texture");return false;}GLsizei widthV = (GLsizei) m_width / 2;GLsizei heightV = (GLsizei) m_height / 2;glActiveTexture(GL_TEXTURE2);glGenTextures(1, &m_textureIdV);glBindTexture(GL_TEXTURE_2D, m_textureIdV);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthV, heightV, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,nullptr);if (!m_textureIdV) {LOGE("OpenGL Error Create V texture");return false;}return true;
}bool OpenglesTexureVideoRender::updateTextures() {if (!m_textureIdY && !m_textureIdU && !m_textureIdV && !createTextures()) return false;LOGI("OpenglesTexureVideoRender updateTextures");if (isDirty) {glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, m_textureIdY);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width, (GLsizei) m_height, 0,GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataY.get());glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, m_textureIdU);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width / 2, (GLsizei) m_height / 2,0,GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataU);glActiveTexture(GL_TEXTURE2);glBindTexture(GL_TEXTURE_2D, m_textureIdV);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width / 2, (GLsizei) m_height / 2,0,GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataV);isDirty = false;return true;}return false;
}int
OpenglesTexureVideoRender::createProgram() {m_program = openGlShader->createProgram();m_vertexShader = openGlShader->vertexShader;m_pixelShader = openGlShader->fraShader;LOGI("OpenglesTexureVideoRender createProgram m_program:%d", m_program);if (!m_program) {LOGE("Could not create program.");return 0;}//Get Uniform Variables Locationm_vertexPos = (GLuint) glGetAttribLocation(m_program, "position");m_textureYLoc = glGetUniformLocation(m_program, "s_textureY");m_textureULoc = glGetUniformLocation(m_program, "s_textureU");m_textureVLoc = glGetUniformLocation(m_program, "s_textureV");m_textureLoc = (GLuint) glGetAttribLocation(m_program, "texcoord");return m_program;
}GLuint OpenglesTexureVideoRender::useProgram() {if (!m_program && !createProgram()) {LOGE("Could not use program.");return 0;}if (isProgramChanged) {glUseProgram(m_program);glVertexAttribPointer(m_vertexPos, 2, GL_FLOAT, GL_FALSE, 0, kVerticek);glEnableVertexAttribArray(m_vertexPos);glUniform1i(m_textureYLoc, 0);glUniform1i(m_textureULoc, 1);glUniform1i(m_textureVLoc, 2);glVertexAttribPointer(m_textureLoc, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoordk);glEnableVertexAttribArray(m_textureLoc);isProgramChanged = false;}return m_program;
}bool OpenglesTexureVideoRender::setSharderPath(const char *vertexPath, const char *fragmentPath) {openGlShader->getSharderPath(vertexPath, fragmentPath);return 0;
}bool OpenglesTexureVideoRender::setSharderStringPath(string vertexPath, string fragmentPath) {openGlShader->getSharderStringPath(vertexPath, fragmentPath);return 0;
}OpenglesTexureVideoRender::OpenglesTexureVideoRender() {openGlShader = new OpenGLShader();
}OpenglesTexureVideoRender::~OpenglesTexureVideoRender() {deleteTextures();delete_program(m_program);
}void OpenglesTexureVideoRender::delete_program(GLuint &program) {if (program) {glUseProgram(0);glDeleteProgram(program);program = 0;}
}void OpenglesTexureVideoRender::deleteTextures() {if (m_textureIdY) {glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, 0);glDeleteTextures(1, &m_textureIdY);m_textureIdY = 0;}if (m_textureIdU) {glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, 0);glDeleteTextures(1, &m_textureIdU);m_textureIdU = 0;}if (m_textureIdV) {glActiveTexture(GL_TEXTURE2);glBindTexture(GL_TEXTURE_2D, 0);glDeleteTextures(1, &m_textureIdV);m_textureIdV = 0;}
}void OpenglesTexureVideoRender::printGLString(const char *name, GLenum s) {const char *v = (const char *) glGetString(s);LOGI("OpenGL %s = %s\n", name, v);
}void OpenglesTexureVideoRender::checkGlError(const char *op) {for (GLint error = glGetError(); error; error = glGetError()) {LOGI("after %s() glError (0x%x)\n", op, error);}
}

        纹理的使用:

        在Filter滤镜的片段着色中沿用着三个关于YUV的s_textureY/s_textureU/s_textureV三个uniform参数,用于创建纹理时的数据传递。

     //Get Uniform Variables Locationm_vertexPos = (GLuint) glGetAttribLocation(m_program, "position");m_textureYLoc = glGetUniformLocation(m_program, "s_textureY");m_textureULoc = glGetUniformLocation(m_program, "s_textureU");m_textureVLoc = glGetUniformLocation(m_program, "s_textureV");m_textureLoc = (GLuint) glGetAttribLocation(m_program, "texcoord");

       多片段着色器程序的传入:

        要实现滤镜效果,会在片段着色器程序(Fragment Shader)中对YUV数据进行各种有意思的转换。这样的话必须传入多个片段着色器程序代码,以供滤镜切换时使用。

bool OpenglesTextureFilterRender::setSharderStringPathes(string vertexPath,vector<string> fragmentPathes) {m_fragmentStringPathes = fragmentPathes;m_vertexStringPath = vertexPath;return OpenglesTexureVideoRender::setSharderStringPath(vertexPath,                                                           m_fragmentStringPathes.front());
}

        片段着色器的切换:

        对滤镜来说关于顶点数据及纹理的顶点数据是不变的,所以在本篇中只讨论顶点程序(Vertex Shader)不变的,当然也可以同时顶点程序也可以变化实现一些动态的效果。等以后think出一些多的idea在实现动态滤镜的效果,到时再写几篇博客分享分享。

        在render函数中切换片段着色器,切换时要把之前的着色器程序删除,然后再传入需要的片段着色器重新走一遍着色器的编译/链接/使用过程。 

void OpenglesTextureFilterRender::render() {if (m_filter != m_prevFilter) {m_prevFilter = m_filter;if (m_filter >= 0 && m_filter < m_fragmentStringPathes.size()) {isProgramChanged = true;delete_program(m_program);setSharderStringPath(m_vertexStringPath, m_fragmentStringPathes.at(m_filter));createProgram();}}OpenglesTexureVideoRender::render();
}

        

二.片段着色器程序GLSL:

        1.YUV数据的真实显示:

        无添加任何滤镜的状态,显示Camera的真实画面:       

#version 320 esprecision mediump float;in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;// https://stackoverflow.com/questions/26695253/when-switching-to-glsl-300-met-the-following-error
//The predefined variable gl_FragColor does not exist anymore in GLSL ES 3.00.
//out vec4 gl_FragColor;
out vec4 FragColor;void main() {float y, u, v, r, g, b;y = texture(s_textureY, v_texcoord).r;u = texture(s_textureU, v_texcoord).r;v = texture(s_textureV, v_texcoord).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;FragColor = vec4(r, g, b, 1.0f);
//    gl_FragColor = vec4(r, g, b, 1.0);}

        2.模糊处理滤镜:        

#version 320 esprecision mediump float;in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;out vec4 FragColor;vec4 YuvToRgb(vec2 uv) {float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;return vec4(r, g, b, 1.0);}void main() {vec4 sample0, sample1, sample2, sample3;float blurStep = 0.5;float step = blurStep / 100.0f;sample0 = YuvToRgb(vec2(v_texcoord.x - step, v_texcoord.y - step));sample1 = YuvToRgb(vec2(v_texcoord.x + step, v_texcoord.y + step));sample2 = YuvToRgb(vec2(v_texcoord.x + step, v_texcoord.y - step));sample3 = YuvToRgb(vec2(v_texcoord.x - step, v_texcoord.y + step));FragColor = (sample0 + sample1 + sample2 + sample3) / 4.0;
}

        3.鱼眼滤镜:        

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;out vec4 FragColor;//鱼眼滤镜
void main() {float aperture = 158.0;float apertureHalf = 0.5 * aperture * (PI / 180.0);float maxFactor = sin(apertureHalf);vec2 uv;vec2 xy = 2.0 * v_texcoord.xy - 1.0;float d = length(xy);if (d < (2.0 - maxFactor)) {d = length(xy * maxFactor);float z = sqrt(1.0 - d * d);float r = atan(d, z) / PI;float phi = atan(xy.y, xy.x);uv.x = r * cos(phi) + 0.5;uv.y = r * sin(phi) + 0.5;} else {uv = v_texcoord.xy;}float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;FragColor = vec4(r, g, b, 1.0);}

        4. 旋流过滤器:          

        

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;//旋流过滤器
void main() {float radius = 200.0;float angle = 0.8;vec2 center = vec2(texSize.x / 2.0, texSize.y / 2.0);vec2 tc = v_texcoord * texSize;tc -= center;float dist = length(tc);if (dist < radius) {float percent = (radius - dist) / radius;float theta = percent * percent * angle * 8.0;float s = sin(theta);float c = cos(theta);tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));}tc += center;float y, u, v, r, g, b;y = texture(s_textureY, tc / texSize).r;u = texture(s_textureU, tc / texSize).r;v = texture(s_textureV, tc / texSize).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;FragColor = vec4(r, g, b, 1.0);}

5.放大镜滤光片:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;vec4 YuvToRgb(vec2 uv) {float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;return vec4(r, g, b, 1.0);}//放大镜滤光片
void main() {float circleRadius = float(0.5);float minZoom = 0.4;float maxZoom = 0.6;vec2 center = vec2(texSize.x / 2.0, texSize.y / 2.0);vec2 uv = v_texcoord;uv.x *= (texSize.x / texSize.y);vec2 realCenter = vec2(0.0, 0.0);realCenter.x = (center.x / texSize.x) * (texSize.x / texSize.y);realCenter.y = center.y / texSize.y;float maxX = realCenter.x + circleRadius;float minX = realCenter.x - circleRadius;float maxY = realCenter.y + circleRadius;float minY = realCenter.y - circleRadius;if (uv.x > minX && uv.x < maxX && uv.y > minY && uv.y < maxY) {float relX = uv.x - realCenter.x;float relY = uv.y - realCenter.y;float ang =  atan(relY, relX);float dist = sqrt(relX * relX + relY * relY);if (dist <= circleRadius) {float newRad = dist * ((maxZoom * dist / circleRadius) + minZoom);float newX = realCenter.x + cos(ang) * newRad;newX *= (texSize.y / texSize.x);float newY = realCenter.y + sin(ang) * newRad;FragColor = YuvToRgb(vec2(newX, newY));} else {FragColor = YuvToRgb(v_texcoord);}} else {FragColor = YuvToRgb(v_texcoord);}}

6.利希滕斯坦过滤器

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;//利希滕斯坦式过滤器
void main() {float size = texSize.x / 75.0;float radius = size * 0.5;vec2 fragCoord = v_texcoord * texSize.xy;vec2 quadPos = floor(fragCoord.xy / size) * size;vec2 quad = quadPos/texSize.xy;vec2 quadCenter = (quadPos + size/2.0);float dist = length(quadCenter - fragCoord.xy);float y, u, v, r, g, b;y = texture(s_textureY, quad).r;u = texture(s_textureU, quad).r;v = texture(s_textureV, quad).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;if (dist > radius) {FragColor = vec4(0.25);} else {FragColor = vec4(r, g, b, 1.0);}}

        7.三角形马赛克滤镜:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;vec4 YuvToRgb(vec2 uv) {float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;return vec4(r, g, b, 1.0);}//三角形马赛克滤镜
void main() {vec2 tileNum = vec2(40.0, 20.0);vec2 uv = v_texcoord;vec2 uv2 = floor(uv * tileNum) / tileNum;uv -= uv2;uv *= tileNum;vec3 color = YuvToRgb(uv2 + vec2(step(1.0 - uv.y, uv.x) / (2.0 * tileNum.x),step(uv.x, uv.y) / (2.0 * tileNum.y))).rgb;FragColor = vec4(color, 1.0);}

8.像素过滤器:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;//像素过滤器
void main() {vec2 pixelSize = vec2(texSize.x/100.0, texSize.y/100.0);vec2 uv = v_texcoord.xy;float dx = pixelSize.x*(1./texSize.x);float dy = pixelSize.y*(1./texSize.y);vec2 coord = vec2(dx*floor(uv.x/dx),dy*floor(uv.y/dy));float y, u, v, r, g, b;y = texture(s_textureY, coord).r;u = texture(s_textureU, coord).r;v = texture(s_textureV, coord).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;FragColor = vec4(r, g, b, 1.0);}

8.交叉缝合过滤器:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;vec4 YuvToRgb(vec2 uv) {float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;return vec4(r, g, b, 1.0);}vec4 CrossStitching(vec2 uv) {float stitchSize = texSize.x / 35.0;int invert = 0;vec4 color = vec4(0.0);float size = stitchSize;vec2 cPos = uv * texSize.xy;vec2 tlPos = floor(cPos / vec2(size, size));tlPos *= size;int remX = int(mod(cPos.x, size));int remY = int(mod(cPos.y, size));if (remX == 0 && remY == 0)tlPos = cPos;vec2 blPos = tlPos;blPos.y += (size - 1.0);if ((remX == remY) || (((int(cPos.x) - int(blPos.x)) == (int(blPos.y) - int(cPos.y))))) {if (invert == 1)color = vec4(0.2, 0.15, 0.05, 1.0);elsecolor = YuvToRgb(tlPos * vec2(1.0 / texSize.x, 1.0 / texSize.y)) * 1.4;} else {if (invert == 1)color = YuvToRgb(tlPos * vec2(1.0 / texSize.x, 1.0 / texSize.y)) * 1.4;elsecolor = vec4(0.0, 0.0, 0.0, 1.0);}return color;}//交叉缝合过滤器
void main() {FragColor = CrossStitching(v_texcoord);}

9.Toonfiy过滤器:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;
const int kHueLevCount = 6;
const int kSatLevCount = 7;
const int kValLevCount = 4;
float hueLevels[kHueLevCount];
float satLevels[kSatLevCount];
float valLevels[kValLevCount];
float edge_thres = 0.2;
float edge_thres2 = 5.0;out vec4 FragColor;vec4 YuvToRgb(vec2 uv) {float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;return vec4(r, g, b, 1.0);}vec3 RGBtoHSV(float r, float g, float b) {float minv, maxv, delta;vec3 res;minv = min(min(r, g), b);maxv = max(max(r, g), b);res.z = maxv;delta = maxv - minv;if (maxv != 0.0)res.y = delta / maxv;else {res.y = 0.0;res.x = -1.0;return res;}if (r == maxv)res.x = ( g - b ) / delta;else if (g == maxv)res.x = 2.0 + ( b - r ) / delta;elseres.x = 4.0 + ( r - g ) / delta;res.x = res.x * 60.0;if(res.x < 0.0)res.x = res.x + 360.0;return res;}vec3 HSVtoRGB(float h, float s, float v ) {int i;float f, p, q, t;vec3 res;if(s == 0.0) {res.x = v;res.y = v;res.z = v;return res;}h /= 60.0;i = int(floor( h ));f = h - float(i);p = v * ( 1.0 - s );q = v * ( 1.0 - s * f );t = v * ( 1.0 - s * ( 1.0 - f ) );if (i == 0) {res.x = v;res.y = t;res.z = p;} else if (i == 1) {res.x = q;res.y = v;res.z = p;} else if (i == 2) {res.x = p;res.y = v;res.z = t;} else if (i == 3) {res.x = p;res.y = q;res.z = v;} else if (i == 4) {res.x = t;res.y = p;res.z = v;} else if (i == 5) {res.x = v;res.y = p;res.z = q;}return res;}float nearestLevel(float col, int mode) {int levCount;if (mode==0) levCount = kHueLevCount;if (mode==1) levCount = kSatLevCount;if (mode==2) levCount = kValLevCount;for (int i=0; i<levCount-1; i++ ) {if (mode==0) {if (col >= hueLevels[i] && col <= hueLevels[i+1]) {return hueLevels[i+1];}}if (mode==1) {if (col >= satLevels[i] && col <= satLevels[i+1]) {return satLevels[i+1];}}if (mode==2) {if (col >= valLevels[i] && col <= valLevels[i+1]) {return valLevels[i+1];}}}}float avgIntensity(vec4 pix) {return (pix.r + pix.g + pix.b)/3.;}vec4 getPixel(vec2 coords, float dx, float dy) {return YuvToRgb(coords + vec2(dx, dy));}float IsEdge(in vec2 coords) {float dxtex = 1.0 / float(texSize.x);float dytex = 1.0 / float(texSize.y);float pix[9];int k = -1;float delta;for (int i=-1; i<2; i++) {for(int j=-1; j<2; j++) {k++;pix[k] = avgIntensity(getPixel(coords,float(i)*dxtex, float(j)*dytex));}}delta = (abs(pix[1]-pix[7]) + abs(pix[5]-pix[3]) + abs(pix[0]-pix[8])+ abs(pix[2]-pix[6]))/4.;return clamp(edge_thres2*delta,0.0,1.0);}//Toonify过滤器
void main() {hueLevels[0] = 0.0;hueLevels[1] = 140.0;hueLevels[2] = 160.0;hueLevels[3] = 240.0;hueLevels[4] = 240.0;hueLevels[5] = 360.0;satLevels[0] = 0.0;satLevels[1] = 0.15;satLevels[2] = 0.3;satLevels[3] = 0.45;satLevels[4] = 0.6;satLevels[5] = 0.8;satLevels[6] = 1.0;valLevels[0] = 0.0;valLevels[1] = 0.3;valLevels[2] = 0.6;valLevels[3] = 1.0;vec2 uv = v_texcoord;vec3 color = YuvToRgb(uv).rgb;vec3 vHSV =  RGBtoHSV(color.r, color.g, color.b);vHSV.x = nearestLevel(vHSV.x, 0);vHSV.y = nearestLevel(vHSV.y, 1);vHSV.z = nearestLevel(vHSV.z, 2);float edg = IsEdge(uv);vec3 vRGB = (edg >= edge_thres) ? vec3(0.0,0.0,0.0) : HSVtoRGB(vHSV.x,vHSV.y,vHSV.z);FragColor = vec4(vRGB.x, vRGB.y, vRGB.z, 1.0);}

10.捕食者热视觉滤镜:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;//捕食者热视觉滤镜
void main() {float y, u, v, r, g, b;y = texture(s_textureY, v_texcoord).r;u = texture(s_textureU, v_texcoord).r;v = texture(s_textureV, v_texcoord).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;vec3 color = vec3(r, g, b);vec2 uv = v_texcoord.xy;vec3 colors[3];colors[0] = vec3(0.,0.,1.);colors[1] = vec3(1.,1.,0.);colors[2] = vec3(1.,0.,0.);float lum = (color.r + color.g + color.b)/3.;int idx = (lum < 0.5) ? 0 : 1;vec3 rgb = mix(colors[idx],colors[idx+1],(lum-float(idx)*0.5)/0.5);FragColor = vec4(rgb, 1.0);}

11.压花过滤器:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;vec4 YuvToRgb(vec2 uv) {float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;return vec4(r, g, b, 1.0);}//压花过滤器
void main() {vec4 color;color.rgb = vec3(0.5);vec2 onePixel = vec2(1.0 / texSize.x, 1.0 / texSize.y);color -= YuvToRgb(v_texcoord - onePixel) * 5.0;color += YuvToRgb(v_texcoord + onePixel) * 5.0;color.rgb = vec3((color.r + color.g + color.b) / 3.0);FragColor = vec4(color.rgb, 1.0);}

12.边缘检测滤波器:

#version 320 esprecision mediump float;
const float PI = 3.1415926535;
in vec2 v_texcoord;uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform vec2 texSize;out vec4 FragColor;vec4 YuvToRgb(vec2 uv) {float y, u, v, r, g, b;y = texture(s_textureY, uv).r;u = texture(s_textureU, uv).r;v = texture(s_textureV, uv).r;u = u - 0.5;v = v - 0.5;r = y + 1.403 * v;g = y - 0.344 * u - 0.714 * v;b = y + 1.770 * u;return vec4(r, g, b, 1.0);}//边缘检测滤波器
void main() {vec2 pos = v_texcoord.xy;vec2 onePixel = vec2(1, 1) / texSize;vec4 color = vec4(0);mat3 edgeDetectionKernel = mat3(-1, -1, -1,-1, 8, -1,-1, -1, -1);for(int i = 0; i < 3; i++) {for(int j = 0; j < 3; j++) {vec2 samplePos = pos + vec2(i - 1 , j - 1) * onePixel;vec4 sampleColor = YuvToRgb(samplePos);sampleColor *= edgeDetectionKernel[i][j];color += sampleColor;}}FragColor = vec4(color.rgb, 1.0);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1535679.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】8——图3,十字链表,邻接多重表

数据结构8——图3&#xff0c;十字链表&#xff0c;邻接多重表 文章目录 数据结构8——图3&#xff0c;十字链表&#xff0c;邻接多重表前言一、十字链表结构例子 复杂例子 二、邻接多重表&#xff08;Adjacency Multilist&#xff09;例子 前言 除了之前的邻接矩阵和邻接表 …

Java抽象类和接口的学习了解

目录 1. 抽象类 1.1 抽象类概念 1.2例子 1.3 抽象类语法 1.被 abstract 修饰的类--抽象类 2.抽象类中被 abstract 修饰的方法--抽象方法&#xff0c;该方法不用给出具体的实现体 3.当一个类中含有抽象方法时&#xff0c;该类必须要abstract修饰 4.抽象类也是类&#xff…

PCIe进阶之TL:Address Spaces, Transaction Types, and Usage

1 Transaction Layer Overview 如上图为PCIe设备的一个分层结构,从上层逻辑看,事务层的关键点是: 流水线式的完整的 split-transaction 协议事务层数据包(TLP)的排序和处理基于信用的流控制机制可选支持的数据中毒功能和端到端数据完整性检测功能事务层包含以下内容: TLP…

828华为云征文|部署在线文件管理器 Spacedrive

828华为云征文&#xff5c;部署在线文件管理器 Spacedrive 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 产品优势1.3 计费模式 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Spacedrive3.1 Spacedrive 介绍3.2 Docker 环境搭建3.3 Spac…

JNI 详细介绍

一 介绍 java调⽤c&#xff0c;c代码可以通过JNIEnv执行java代码。 安卓NDK 已经对JNI环境进行了集成&#xff0c;我们可以通过android studio来快速搭建一个项目。 二 项目搭建 打开android studio 创建工程&#xff0c;创建工程选择模板Native C 三 模板格式介绍 生成的…

基于Python实现的一个电影知识库QA系统

1. 实现效果 1. 图形展示 这是使用echarts.js 来实现的自定义页面的图谱展示&#xff0c;当然还有其他的库也能实现类似的效果&#xff0c;这里看各位的选择。 这里我在每个实体之间都实现了双层关系的绑定&#xff0c;这对于后面实现检索会有点帮助 2. 实体搜索展示 这里…

数字孪生卷进了天气预报行业

在视频中&#xff0c;上一秒主持人还在大屏幕前正常播报天气。下一秒&#xff0c;场景切换&#xff0c;主持人走到旁边&#xff0c;演播室边上呈现出狂风骤雨的街道&#xff0c;随着播报&#xff0c;一棵被台风吹倒的树“砸进”演播室&#xff0c;营造出一种惊险的感觉&#xf…

Java | Leetcode Java题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; class Solution {public String toHex(int num) {if (num 0) {return "0";}StringBuffer sb new StringBuffer();for (int i 7; i > 0; i --) {int val (num >> (4 * i)) & 0xf;if (sb.length() > 0 || val …

Java | Leetcode Java题解之第406题根据身高重建队列

题目&#xff1a; 题解&#xff1a; class Solution {public int[][] reconstructQueue(int[][] people) {Arrays.sort(people, new Comparator<int[]>() {public int compare(int[] person1, int[] person2) {if (person1[0] ! person2[0]) {return person2[0] - perso…

驾驶员注意力分神状态检测系统源码分享

驾驶员注意力分神状态检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of …

springboot医院预约挂号系统 ---附源码73444

目录 1 绪论 1.1 研究背景 1.2研究意义 1.3论文结构与章节安排 2 医院预约挂号系统系统分析 2.1 可行性分析 2.2 系统功能分析 2.3 系统用例分析 2.4 系统流程分析 2.5本章小结 3 医院预约挂号系统总体设计 3.1 系统功能模块设计 3.2 数据库设计 3.4本章小结 4 医…

【文件系统】软硬链接

目录 1. 汇总 ext2 文件系统2. 文件名 与 inode 的关联3. 软硬链接3.1 理解硬链接3.2 理解软链接3.3 软硬链接的应用场景 1. 汇总 ext2 文件系统 新建文件 一个文件一定是在某个路径下创建的&#xff0c;有了路径&#xff0c;就能够知道该新建文件所在分区&#xff0c;然后再查…

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef 1. AOSPXRef1.1. http://aospxref.com/android-14.0.0_r2/1.2. build/envsetup.sh 2. AndroidXRef2.1. http://androidxref.com/9.0.0_r3/2.2. build/envsetup.sh 3. HELLO AndroidReferences 1. AOSPXRef http://aospx…

JAVA基础面试题总结(十五)——设计模式

面试专题-设计模式 前言 在平时的开发中&#xff0c;涉及到设计模式的有两块内容&#xff0c;第一个是我们平时使用的框架&#xff08;比如spring、mybatis等&#xff09;&#xff0c;第二个是我们自己开发业务使用的设计模式。 面试官一般比较关心的是你在开发过程中&#…

浮动元素详解

浮动元素 代码实现&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>浮动元素</title><style>#container1 {width: 400px;height: 50px;background-color: lightgrey;border: 1px solid;}#contai…

828华为云征文|华为云Flexus云服务器X实例之openEuler系统下dufs文件服务器

828华为云征文&#xff5c;华为云Flexus云服务器X实例之openEuler系统下dufs文件服务器 一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、dufs介绍2.1 dufs简介2.2 dufs特点2.3 使用场景 三、本次实践…

学习整理vue前端框架项目目录结构的含义

学习整理vue前端框架项目目录结构的含义 1、目录结构2、结构含义 1、目录结构 2、结构含义

大模型大侦探-一次丝滑的探图记录

文章目录 缘起调查深入确认总结 缘起 最近找到了我的一台老笔记本电脑&#xff0c;竟然还能开机&#xff0c;是XP的。里面有一个桌面&#xff0c;叫做panMilk: 这太美了&#xff0c;但这是哪里&#xff1f;这个问题在20年前就困扰了我&#xff0c;不得答案。这些年学校、公司的…

CorrMatch复现

复现结果–Full&#xff1a;81.78327847863439&#xff0c;成功 U2PL’s splits计算量太大&#xff0c;不建议复现

美团图床设置教程

大厂图床&#xff0c;CDN加速 项目地址&#xff1a;https://github.com/woniu336/mt-img 使用方法 在mt.php填上你的token即可&#xff0c;然后打开index.html上传图片 获取token方法 注册https://czz.meituan.com/发布视频&#xff0c;上传封面&#xff0c;注意在上传封面后…