热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

我用OpenGL实现了那些年流行的相机滤镜

想要成为一名优秀的Android开发,你需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样~。OpenGLES相机基础滤镜上文中我们通过I

想要成为一名优秀的Android开发,你需要一份完备的 知识体系,在这里,让我们一起成长为自己所想的那样~。

OpenGL ES 相机基础滤镜

上文中我们通过 ImageReader 获取到 Camera2 预览的 YUV 数据,然后利用 OpenGLES 渲染实现相机预览,这一节将利用 GLSL (OpenGL 着色器语言)基于不同的着色器实现多种基础滤镜。

内建函数 函数说明
float distance (genType p0, genType p1) 计算向量 p0 ,p1 之间的距离
float length (genType x) 返回向量 x 的长度
genType floor (genType x) 返回小于等于 x 的最大整数值
genType ceil (genType x) 返回大于等于 x 的最小整数值
genType mod (genType x, float y) 返回 x – y * floor (x / y) ,即求模计算 %
float dot (genType x, genType y) 向量 x ,y 之间的点积
vec3 cross (vec3 x, vec3 y) 向量 x ,y 之间的叉积
genType normalize (genType x) 标准化向量,返回一个方向和 x 相同但长度为 1 的向量

GLSL 一些使用频率比较高的内建函数

动态网格

我用 OpenGL 实现了那些年流行的相机滤镜

动态网格

动态网格滤镜主要是将纹理划分为多个网格,然后根据一个偏移量动态改变网格线的宽度。mod 和 floor 为 GLSL 的内建函数,分别表示取模和取整。需要注意的是,计算之前需要将纹理坐标系转换为图片坐标系,保证网格没有被拉伸。

//dynimic mesh 动态网格着色器
#version 100
precision highp float;
varying vec2 v_texcoord;
uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform float u_offset;//偏移量
uniform vec2 texSize;//纹理尺寸
vec4 YuvToRgb(vec2 uv) {
    float y, u, v, r, g, b;
    y = texture2D(s_textureY, uv).r;
    u = texture2D(s_textureU, uv).r;
    v = texture2D(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 imgTexCoord = v_texcoord * texSize;//将纹理坐标系转换为图片坐标系
    float sideLength = texSize.y / 6.0;//网格的边长
    float maxOffset = 0.15 * sideLength;//设置网格线宽度的最大值
    float x = mod(imgTexCoord.x, floor(sideLength));
    float y = mod(imgTexCoord.y, floor(sideLength));

    float offset = u_offset * maxOffset;

    if(offset 

分屏

我用 OpenGL 实现了那些年流行的相机滤镜

四分屏

分屏滤镜的原理是在多个指定区域内对整个纹理进行下采样(缩小),从而实现整个图像在多个区域内多次显示。

//分屏(四分屏)
#version 100
precision highp float;
varying vec2 v_texcoord;
uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
vec4 YuvToRgb(vec2 uv) {
    float y, u, v, r, g, b;
    y = texture2D(s_textureY, uv).r;
    u = texture2D(s_textureU, uv).r;
    v = texture2D(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 newTexCoord = v_texcoord;
    if(newTexCoord.x 

缩放的圆

我用 OpenGL 实现了那些年流行的相机滤镜

缩放的圆

缩放的圆效果实现主要依赖偏移量来动态改变圆半径的大小,在半径区域内对纹理采样显示图像,在半径区域外返回一个固定颜色(如白色)。distance 也是 GLSL 的内建函数,用于计算两点之间的距离。另外需要注意是,在计算之前首先要将纹理坐标系转换为图片坐标系,否则绘制的将会是一个椭圆形图像(图像宽高不同的情况下),想一想为什么会这样?

//scale circle 缩放的圆
#version 100
precision highp float;
varying vec2 v_texcoord;
uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;
uniform float u_offset;
uniform vec2 texSize;
vec4 YuvToRgb(vec2 uv) {
    float y, u, v, r, g, b;
    y = texture2D(s_textureY, uv).r;
    u = texture2D(s_textureU, uv).r;
    v = texture2D(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 imgTex = v_texcoord * texSize;//将纹理坐标系转换为图片坐标系
    float r = (u_offset + 0.208 ) * texSize.x;
    if(distance(imgTex, vec2(texSize.x / 2.0, texSize.y / 2.0)) 

在计算之前首先要将纹理坐标系转换为图片坐标系,其原因在于纹理纵横坐标的取值范围均为 [0, 1] ,从数值上看纹理的纵横方向长度相同,但是在 OpenGL 采样时,图像的宽高比往往不是 1 ,这就导致了数值相同的纵横坐标,对应不同的采样权重,出现了预期绘制圆形而实际上却绘制出椭圆的情况。

本文在开源项目:https://github.com/Android-Alvin/Android-LearningNotes 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…


推荐阅读
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 【MicroServices】【Arduino】装修甲醛检测,ArduinoDart甲醛、PM2.5、温湿度、光照传感器等,数据记录于SD卡,Python数据显示,UI5前台,微服务后台……
    这篇文章介绍了一个基于Arduino的装修甲醛检测项目,使用了ArduinoDart甲醛、PM2.5、温湿度、光照传感器等硬件,并将数据记录于SD卡,使用Python进行数据显示,使用UI5进行前台设计,使用微服务进行后台开发。该项目还在不断更新中,有兴趣的可以关注作者的博客和GitHub。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
author-avatar
攻玉是我_944
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有