Skip to content

Commit

Permalink
add lux related filters
Browse files Browse the repository at this point in the history
  • Loading branch information
xu.shuifeng authored and xu.shuifeng committed Jul 13, 2018
1 parent 09e95e5 commit 09b320f
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 0 deletions.
24 changes: 24 additions & 0 deletions MetalFilters.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@
A3A068E520CFCE3800A2DF76 /* HorizontalSliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A068E420CFCE3800A2DF76 /* HorizontalSliderView.swift */; };
A3C44C3220CE7AFB0036E8E8 /* MTBasicAdjustFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C44C3120CE7AFB0036E8E8 /* MTBasicAdjustFilter.swift */; };
A3C44C3420CE7B520036E8E8 /* MTBasicAdjustFilter.metal in Sources */ = {isa = PBXBuildFile; fileRef = A3C44C3320CE7B520036E8E8 /* MTBasicAdjustFilter.metal */; };
A3E572B120F8B5B400294AE4 /* MTAntiLuxFilter.metal in Sources */ = {isa = PBXBuildFile; fileRef = A3E572AF20F8B5B300294AE4 /* MTAntiLuxFilter.metal */; };
A3E572B220F8B5B400294AE4 /* MTAntiLuxFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3E572B020F8B5B300294AE4 /* MTAntiLuxFilter.swift */; };
A3E572B720F8B5BF00294AE4 /* MTStarlightFilter.metal in Sources */ = {isa = PBXBuildFile; fileRef = A3E572B320F8B5BE00294AE4 /* MTStarlightFilter.metal */; };
A3E572B820F8B5BF00294AE4 /* MTLuxBlendFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3E572B420F8B5BE00294AE4 /* MTLuxBlendFilter.swift */; };
A3E572B920F8B5BF00294AE4 /* MTLuxBlendFilter.metal in Sources */ = {isa = PBXBuildFile; fileRef = A3E572B520F8B5BE00294AE4 /* MTLuxBlendFilter.metal */; };
A3E572BA20F8B5BF00294AE4 /* MTStarlightFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3E572B620F8B5BE00294AE4 /* MTStarlightFilter.swift */; };
A3E9714E20D6064300D66B87 /* MTFilterGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3E9714D20D6064300D66B87 /* MTFilterGroup.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -233,6 +239,12 @@
A3A068E420CFCE3800A2DF76 /* HorizontalSliderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalSliderView.swift; sourceTree = "<group>"; };
A3C44C3120CE7AFB0036E8E8 /* MTBasicAdjustFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MTBasicAdjustFilter.swift; sourceTree = "<group>"; };
A3C44C3320CE7B520036E8E8 /* MTBasicAdjustFilter.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = MTBasicAdjustFilter.metal; sourceTree = "<group>"; };
A3E572AF20F8B5B300294AE4 /* MTAntiLuxFilter.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = MTAntiLuxFilter.metal; sourceTree = "<group>"; };
A3E572B020F8B5B300294AE4 /* MTAntiLuxFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTAntiLuxFilter.swift; sourceTree = "<group>"; };
A3E572B320F8B5BE00294AE4 /* MTStarlightFilter.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = MTStarlightFilter.metal; sourceTree = "<group>"; };
A3E572B420F8B5BE00294AE4 /* MTLuxBlendFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTLuxBlendFilter.swift; sourceTree = "<group>"; };
A3E572B520F8B5BE00294AE4 /* MTLuxBlendFilter.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = MTLuxBlendFilter.metal; sourceTree = "<group>"; };
A3E572B620F8B5BE00294AE4 /* MTStarlightFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTStarlightFilter.swift; sourceTree = "<group>"; };
A3E9714D20D6064300D66B87 /* MTFilterGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MTFilterGroup.swift; sourceTree = "<group>"; };
B817D3CCD2892291BA74BE47 /* Pods_MetalFilters.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MetalFilters.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -313,6 +325,12 @@
A38FC79820D1C567002CA905 /* MTTintColor.swift */,
A3710C5D20D3DADF00FC0025 /* MTImageOverlayFilter.swift */,
A3710C5F20D3DAF800FC0025 /* MTImageOverlayFilter.metal */,
A3E572AF20F8B5B300294AE4 /* MTAntiLuxFilter.metal */,
A3E572B020F8B5B300294AE4 /* MTAntiLuxFilter.swift */,
A3E572B520F8B5BE00294AE4 /* MTLuxBlendFilter.metal */,
A3E572B420F8B5BE00294AE4 /* MTLuxBlendFilter.swift */,
A3E572B320F8B5BE00294AE4 /* MTStarlightFilter.metal */,
A3E572B620F8B5BE00294AE4 /* MTStarlightFilter.swift */,
);
path = MTFilter;
sourceTree = "<group>";
Expand Down Expand Up @@ -582,6 +600,7 @@
A32F2BFD20D260DC0018C281 /* FilterTintColorControl.swift in Sources */,
A391B32420CE4CCA00E6FD67 /* MTInkwellFilter.metal in Sources */,
A391B2D920CE4CCA00E6FD67 /* MTVesperVideoFilter.swift in Sources */,
A3E572B820F8B5BF00294AE4 /* MTLuxBlendFilter.swift in Sources */,
A391B2DC20CE4CCA00E6FD67 /* MTXpro2Filter.swift in Sources */,
A38FC65A20CB7979002CA905 /* MainViewController.swift in Sources */,
A3A068E520CFCE3800A2DF76 /* HorizontalSliderView.swift in Sources */,
Expand All @@ -608,6 +627,7 @@
A391B2F720CE4CCA00E6FD67 /* MTInkwellFilter.swift in Sources */,
A391B30320CE4CCA00E6FD67 /* MTGinzaVideoFilter.metal in Sources */,
A391B2DA20CE4CCA00E6FD67 /* MTEarlybirdFilter.metal in Sources */,
A3E572BA20F8B5BF00294AE4 /* MTStarlightFilter.swift in Sources */,
A3E9714E20D6064300D66B87 /* MTFilterGroup.swift in Sources */,
A391B32820CE4CCA00E6FD67 /* MTNashvilleFilter.swift in Sources */,
A391B2E920CE4CCA00E6FD67 /* MTAmaroFilter.metal in Sources */,
Expand All @@ -624,6 +644,7 @@
A391B30420CE4CCA00E6FD67 /* MTLoFiFilter.swift in Sources */,
A38FC66620CBEB0E002CA905 /* AlbumPhotoViewController.swift in Sources */,
A30D742320D0EC2A00824A1A /* MTLocalLaplacianFilter.metal in Sources */,
A3E572B920F8B5BF00294AE4 /* MTLuxBlendFilter.metal in Sources */,
A391B32720CE4CCA00E6FD67 /* MTNormalFilter.metal in Sources */,
A391B31220CE4CCA00E6FD67 /* MTMoonVideoFilter.swift in Sources */,
A391B2E020CE4CCA00E6FD67 /* MTSierraFilter.swift in Sources */,
Expand All @@ -646,6 +667,7 @@
A391B32520CE4CCA00E6FD67 /* MTMoonVideoFilter.metal in Sources */,
A30D742120D0EC1C00824A1A /* MTLocalLaplacianFilter.swift in Sources */,
A391B31820CE4CCA00E6FD67 /* MTSlumberFilter.metal in Sources */,
A3E572B220F8B5B400294AE4 /* MTAntiLuxFilter.swift in Sources */,
A3700A2D20C91791005300B8 /* MTFilter.swift in Sources */,
A391B2E120CE4CCA00E6FD67 /* MTNormalFilter.swift in Sources */,
A391B2F420CE4CCA00E6FD67 /* MTHefeFilter.metal in Sources */,
Expand All @@ -669,7 +691,9 @@
A38FC66820CBFBEB002CA905 /* FilterPickerCell.swift in Sources */,
A391B32120CE4CCA00E6FD67 /* MTWaldenFilter.metal in Sources */,
A391B2EE20CE4CCA00E6FD67 /* MTKelvinFilter.swift in Sources */,
A3E572B120F8B5B400294AE4 /* MTAntiLuxFilter.metal in Sources */,
A391B31A20CE4CCA00E6FD67 /* MTVesperVideoFilter.metal in Sources */,
A3E572B720F8B5BF00294AE4 /* MTStarlightFilter.metal in Sources */,
A3C44C3220CE7AFB0036E8E8 /* MTBasicAdjustFilter.swift in Sources */,
A391B30E20CE4CCA00E6FD67 /* MTPerpetuaFilter.swift in Sources */,
A391B2FD20CE4CCA00E6FD67 /* MTDogpatchVideoFilter.swift in Sources */,
Expand Down
85 changes: 85 additions & 0 deletions MetalFilters/MTFilter/MTAntiLuxFilter.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// MTAntiLuxFilter.metal
// MetalFilters
//
// Created by xu.shuifeng on 2018/6/13.
// Copyright © 2018 shuifeng.me. All rights reserved.
//

#include <metal_stdlib>
#include "MTIShaderLib.h"
#include "../Filters/IFShaderLib.h"
using namespace metalpetal;

// see: http://en.wikipedia.org/wiki/Adaptive_histogram_equalization
// return the point when the CDF crosses 0.5, the center of mass of the histogram.
// we'll adjust contrast around this point as the center.
float histogramCenter(texture2d<float, access::sample> cdfTexture, float2 coordinate, float brightness) {
const float xHalfPix = 0.001953125; // (1.0/256.0)/2.0;
const float yHalfPix = .03125; // (1.0/16.0)/2.0;
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::linear);
brightness = brightness + xHalfPix;

// find the coordinate within the interpolation mesh
coordinate = clamp(coordinate, 0.125, 1.0 - 0.125001) - 0.125;
coordinate = coordinate * (3.0 / (1.0-0.125*2.0));
float2 weight = fract(coordinate); // the fractional part are our interpolation weights
coordinate = floor(coordinate); // floor to get the top-right corner

// compute the 4 corners of the mesh we'll be interpolating
// tl = top-left, tr = top-right etc
float tl = float(coordinate.y*4.0 + coordinate.x)/16.0 + yHalfPix;
float tr = float(coordinate.y*4.0 + coordinate.x + 1.0)/16.0 + yHalfPix;
float bl = float((coordinate.y + 1.0)*4.0 + coordinate.x)/16.0 + yHalfPix;
float br = float((coordinate.y + 1.0)*4.0 + coordinate.x + 1.0)/16.0 + yHalfPix;

// obtain the cdf center values of the 4 corners
float4 b1 = cdfTexture.sample(s, float2(1.0, tl));
float4 b2 = cdfTexture.sample(s, float2(1.0, tr));
float4 b3 = cdfTexture.sample(s, float2(1.0, bl));
float4 b4 = cdfTexture.sample(s, float2(1.0, br));

// the fourth channel, "a", is the histogram midpoint

// linearly interpolate to obtain the final brightness
float c1_2 = mix(b1.a, b2.a, weight.x);
float c3_4 = mix(b3.a, b4.a, weight.x);
return mix(c1_2, c3_4, weight.y);
}

fragment float4 MTAntiLuxFilterFragment(VertexOut vertexIn [[ stage_in ]],
texture2d<float, access::sample> inputTexture [[ texture(0) ]],
texture2d<float, access::sample> blurred [[ texture(1) ]],
texture2d<float, access::sample> cdf [[ texture(2) ]],
constant float & filterStrength [[ buffer(0) ]],
sampler textureSampler [[ sampler(0) ]])
{
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::linear);
float4 texel = inputTexture.sample(s, vertexIn.textureCoordinate);
float3 hsv = rgb_to_hsv(texel.rgb);
float3 blurredTexel = blurred.sample(s, vertexIn.textureCoordinate).rgb;
float blurredLum = (blurredTexel.r + blurredTexel.g + blurredTexel.b)/3.0;
// boost highlights and shadows
// first with a mask over regions, don't boost a bright pixel in a shadow region or a dark pixel in a highlight region
float shadowMask = smoothstep(0.5, 0.0, blurredLum); // mask for "shadow areas"
float highlightMask = smoothstep(0.5, 1.0, blurredLum); // mask for "highlight areas"

// then adjust the luminace curve
float srcDarkness = smoothstep(0.0, 0.25, hsv.z) * smoothstep(0.5, 0.25, hsv.z); // lerp on how dark this pixel is
float srcHighlightness = smoothstep(0.50, 0.85, hsv.z); // lery on how bright this pixel is
hsv.z = hsv.z + srcDarkness * 0.14 * shadowMask;
hsv.z = hsv.z + srcHighlightness * 0.14 * highlightMask;

// adjust saturation
hsv.y = min(hsv.y * 0.825, 1.0);
// adjust contrast centered around the CDF
float flatBright = histogramCenter(cdf, vertexIn.textureCoordinate, hsv.z);
hsv.z = mix(hsv.z, flatBright, 0.175);

float3 newRgb = hsv_to_rgb(hsv);
// fade in a recycled paper gray colored overlay, the max is for a "lighten" blend mode
newRgb = mix(newRgb, max(newRgb, float3(0.651, 0.615, 0.580)), 0.18);
texel.rgb = mix(texel.rgb, newRgb, filterStrength);

return texel;
}
9 changes: 9 additions & 0 deletions MetalFilters/MTFilter/MTAntiLuxFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//
// MTAntiLuxFilter.swift
// MetalFilters
//
// Created by xu.shuifeng on 2018/6/13.
// Copyright © 2018 shuifeng.me. All rights reserved.
//

import Foundation
28 changes: 28 additions & 0 deletions MetalFilters/MTFilter/MTLuxBlendFilter.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// MTLuxBlendFilter.metal
// MetalFilters
//
// Created by xu.shuifeng on 2018/6/13.
// Copyright © 2018 shuifeng.me. All rights reserved.
//

#include <metal_stdlib>
#include "MTIShaderLib.h"
using namespace metalpetal;

fragment float4 MTLuxBlendFilterFragment(VertexOut vertexIn [[ stage_in ]],
texture2d<float, access::sample> inputTexture [[ texture(0) ]],
texture2d<float, access::sample> antilux [[ texture(1) ]],
texture2d<float, access::sample> starlight [[ texture(2) ]],
constant float & luxBlendAmount [[ buffer(0) ]],
sampler textureSampler [[ sampler(0) ]])
{
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::linear);
float4 texel = inputTexture.sample(s, vertexIn.textureCoordinate);
if (luxBlendAmount >= 0.0) {
texel = mix(texel, starlight.sample(s, vertexIn.textureCoordinate), luxBlendAmount);
} else {
texel = mix(texel, antilux.sample(s, vertexIn.textureCoordinate), -luxBlendAmount);
}
return texel;
}
18 changes: 18 additions & 0 deletions MetalFilters/MTFilter/MTLuxBlendFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// MTLuxBlendFilter.swift
// MetalFilters
//
// Created by xu.shuifeng on 2018/6/13.
// Copyright © 2018 shuifeng.me. All rights reserved.
//

import Foundation

class MTLuxBlendFilter: MTFilter {

var luxBlendAmount: Float = 0

override var parameters: [String : Any] {
return ["luxBlendAmount": luxBlendAmount]
}
}
69 changes: 69 additions & 0 deletions MetalFilters/MTFilter/MTStarlightFilter.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// MTStarlightFilter.metal
// MetalFilters
//
// Created by xu.shuifeng on 2018/6/13.
// Copyright © 2018 shuifeng.me. All rights reserved.
//

#include <metal_stdlib>
#include "MTIShaderLib.h"
#include "../Filters/IFShaderLib.h"
using namespace metalpetal;

// see: http://en.wikipedia.org/wiki/Adaptive_histogram_equalization
float clahe2D(texture2d<float, access::sample> cdfTexture, float2 coordinate, float brightness) {
const float xHalfPix = 0.001953125; // (1.0/256.0)/2.0;
const float yHalfPix = .03125; // (1.0/16.0)/2.0;
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::linear);
brightness = brightness + xHalfPix;

// find the coordinate within the interpolation mesh
coordinate = clamp(coordinate, 0.125, 1.0 - 0.125001) - 0.125;
coordinate = coordinate * (3.0 / (1.0-0.125*2.0));
float2 weight = fract(coordinate); // the fractional part are our interpolation weights
coordinate = floor(coordinate); // floor to get the top-right corner

// compute the 4 corners of the mesh we'll be interpolating
// tl = top-left, tr = top-right etc
float tl = float(coordinate.y*4.0 + coordinate.x)/16.0 + yHalfPix;
float tr = float(coordinate.y*4.0 + coordinate.x + 1.0)/16.0 + yHalfPix;
float bl = float((coordinate.y + 1.0)*4.0 + coordinate.x)/16.0 + yHalfPix;
float br = float((coordinate.y + 1.0)*4.0 + coordinate.x + 1.0)/16.0 + yHalfPix;

// obtain the cdf values of the 4 corners
float4 b1 = cdfTexture.sample(s, float2(brightness, tl));
float4 b2 = cdfTexture.sample(s, float2(brightness, tr));
float4 b3 = cdfTexture.sample(s, float2(brightness, bl));
float4 b4 = cdfTexture.sample(s, float2(brightness, br));

// Commented out for efficiency and subbed in
//float cdf = cdfColor.r;
//float cdfMin = cdfColor.b;

// FIXME: this looks wrong!
float c1 = ((b1.r - b1.b) / (1.0 - b1.b));
float c2 = ((b2.r - b2.b) / (1.0 - b2.b));
float c3 = ((b3.r - b3.b) / (1.0 - b3.b));
float c4 = ((b4.r - b4.b) / (1.0 - b4.b));

// linearly interpolate to obtain the final brightness
float c1_2 = mix(c1, c2, weight.x);
float c3_4 = mix(c3, c4, weight.x);
return mix(c1_2, c3_4, weight.y);
}

fragment float4 MTStarlightFilterFragment(VertexOut vertexIn [[ stage_in ]],
texture2d<float, access::sample> inputTexture [[ texture(0) ]],
texture2d<float, access::sample> cdf [[ texture(1) ]],
constant float & filterStrength [[ buffer(0) ]],
sampler textureSampler [[ sampler(0) ]])
{
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::linear);
float4 texel = inputTexture.sample(s, vertexIn.textureCoordinate);
float3 hsv = rgb_to_hsv(texel.rgb);
hsv.z = clahe2D(cdf, vertexIn.textureCoordinate, hsv.z);
hsv.y = min(hsv.y*1.2, 1.0);
texel.rgb = mix(texel.rgb, hsv_to_rgb(hsv), filterStrength);
return texel;
}
13 changes: 13 additions & 0 deletions MetalFilters/MTFilter/MTStarlightFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// MTStarlightFilter.swift
// MetalFilters
//
// Created by xu.shuifeng on 2018/6/13.
// Copyright © 2018 shuifeng.me. All rights reserved.
//

import Foundation

class MTStarlightFilter: MTFilter {

}

0 comments on commit 09b320f

Please sign in to comment.