You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 16壁纸设置中DUOTONE与COLOR WASH滤镜算法实现问询

DUOTONE与COLOR WASH滤镜的实现方法

一、GLSL着色器实现

1. DUOTONE(双色调)滤镜

双色调滤镜通过将图像灰度值映射为两种指定颜色的渐变实现:暗部使用一种颜色,亮部使用另一种颜色,中间灰度按比例混合两种颜色。结合你提供的黑白滤镜示例,以下是具体实现:

#version 300 es
precision mediump float;
uniform sampler2D uTextureUnit;
// 暗部颜色参数
uniform vec3 uShadowColor;
// 亮部颜色参数
uniform vec3 uHighlightColor;
in vec2 vTexCoord;
out vec4 vFragColor;

void main() {
    vec4 textureColor = texture(uTextureUnit, vTexCoord);
    // 计算像素灰度值(采用ITU-R BT.601标准权重)
    float gray = dot(textureColor.rgb, vec3(0.299, 0.587, 0.114));
    // 按灰度值混合暗部与亮部颜色
    vec3 duotoneColor = mix(uShadowColor, uHighlightColor, gray);
    vFragColor = vec4(duotoneColor, textureColor.a);
}

你可以通过修改uShadowColor和uHighlightColor参数调整配色,比如暗部设为深蓝、亮部设为暖黄,就能得到经典复古双色调效果。

2. COLOR WASH(色彩冲洗)滤镜

色彩冲洗滤镜的核心是给图像叠加统一色调,同时保留原图像的明暗层次,常见于复古胶片风格。以下是两种常用实现方式:

方式一:灰度映射式色彩冲洗

直接用原图像灰度值缩放目标色调,保留明暗细节:

#version 300 es
precision mediump float;
uniform sampler2D uTextureUnit;
// 目标冲洗色调
uniform vec3 uWashColor;
in vec2 vTexCoord;
out vec4 vFragColor;

void main() {
    vec4 textureColor = texture(uTextureUnit, vTexCoord);
    float gray = dot(textureColor.rgb, vec3(0.299, 0.587, 0.114));
    // 用灰度值控制色调亮度,保留明暗层次
    vec3 washColor = uWashColor * gray;
    vFragColor = vec4(washColor, textureColor.a);
}

方式二:色相偏移式色彩冲洗

通过调整色相统一图像色系,同时保留原色彩饱和度与亮度:

#version 300 es
precision mediump float;
uniform sampler2D uTextureUnit;
// 色相偏移值(范围0~1,对应0~360度)
uniform float uHueShift;
in vec2 vTexCoord;
out vec4 vFragColor;

// RGB转HSV辅助函数
vec3 rgb2hsv(vec3 c) {
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

// HSV转RGB辅助函数
vec3 hsv2rgb(vec3 c) {
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

void main() {
    vec4 textureColor = texture(uTextureUnit, vTexCoord);
    vec3 hsv = rgb2hsv(textureColor.rgb);
    // 偏移色相,保留饱和度与明度
    hsv.x = fract(hsv.x + uHueShift);
    vec3 washColor = hsv2rgb(hsv);
    vFragColor = vec4(washColor, textureColor.a);
}

二、LUT文件的生成与使用

LUT(色彩查找表)是预计算色彩映射的方案,适合复杂滤镜效果的快速复用与调整。

1. 生成LUT文件

方法一:Photoshop可视化制作

  1. 创建标准LUT模板:可使用16x16x16的3D LUT模板(行业通用),或256x256的2D LUT模板。
  2. 应用滤镜效果:
    • 双色调:给模板添加「双色调」调整层,设置暗部与亮部颜色。
    • 色彩冲洗:添加「色彩平衡」「色相/饱和度」调整层,或用纯色叠加层(混合模式选「颜色」或「柔光」)。
  3. 导出LUT:将调整后的模板导出为.cube格式(3D LUT标准格式),或.png格式的2D LUT。

方法二:代码批量生成(Python示例)

通过代码自定义算法生成LUT,适合批量或复杂效果:

import numpy as np

# 生成16x16x16的3D LUT
lut_size = 16
lut = np.zeros((lut_size, lut_size, lut_size, 3), dtype=np.float32)

# 定义双色调配色
shadow_color = np.array([0.1, 0.2, 0.4])  # 深蓝
highlight_color = np.array([0.9, 0.7, 0.3])  # 暖黄

for b in range(lut_size):
    for g in range(lut_size):
        for r in range(lut_size):
            # 计算当前RGB值的灰度
            gray = 0.299 * (r / lut_size) + 0.587 * (g / lut_size) + 0.114 * (b / lut_size)
            # 混合双色调颜色
            lut[b, g, r] = shadow_color * (1 - gray) + highlight_color * gray

# 保存为.cube格式
with open("duotone_lut.cube", "w") as f:
    f.write("TITLE \"Duotone Filter LUT\"\n")
    f.write(f"LUT_3D_SIZE {lut_size}\n")
    for b in range(lut_size):
        for g in range(lut_size):
            for r in range(lut_size):
                f.write(f"{lut[b,g,r,0]:.6f} {lut[b,g,r,1]:.6f} {lut[b,g,r,2]:.6f}\n")

2. GLSL中使用LUT

将生成的LUT文件加载为纹理后,即可在着色器中采样使用:

#version 300 es
precision mediump float;
uniform sampler2D uTextureUnit;
uniform sampler2D uLUTTexture;
in vec2 vTexCoord;
out vec4 vFragColor;

void main() {
    vec4 textureColor = texture(uTextureUnit, vTexCoord);
    float lut_size = 16.0;
    float half_step = 0.5 / lut_size;

    // 计算LUT采样坐标
    vec2 uv_r = vec2(textureColor.r, textureColor.b) * (lut_size - 1.0)/lut_size + half_step;
    vec2 uv_g = vec2(textureColor.g, textureColor.b) * (lut_size - 1.0)/lut_size + half_step;

    // 采样LUT获取映射后的颜色分量
    vec3 r_channel = texture(uLUTTexture, uv_r).rgb;
    vec3 g_channel = texture(uLUTTexture, uv_g).rgb;
    vec3 b_channel = texture(uLUTTexture, vec2(textureColor.b, 0.0)).rgb;

    vec3 finalColor = vec3(r_channel.r, g_channel.g, b_channel.b);
    vFragColor = vec4(finalColor, textureColor.a);
}

加载LUT纹理时,需设置纹理过滤方式为GL_LINEAR,避免出现色块断层。

内容的提问来源于stack exchange,提问作者kevinzhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:45:39