Skip to content

Commit 5000f6b

Browse files
committed
Kuwahara filters
Added both Kuwahara filters and the emboss filter.
1 parent a2c9de6 commit 5000f6b

File tree

7 files changed

+549
-18
lines changed

7 files changed

+549
-18
lines changed

examples/Mac/FilterShowcase/FilterShowcase/FilterOperations.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -712,16 +712,16 @@ let filterOperations: Array<FilterOperationInterface> = [
712712
return nil
713713
})
714714
),
715-
// FilterOperation(
716-
// filter:{EmbossFilter()},
717-
// listName:"Emboss",
718-
// titleName:"Emboss",
719-
// sliderConfiguration:.enabled(minimumValue:0.0, maximumValue:5.0, initialValue:1.0),
720-
// sliderUpdateCallback: {(filter, sliderValue) in
721-
// filter.intensity = sliderValue
722-
// },
723-
// filterOperationType:.singleInput
724-
// ),
715+
FilterOperation(
716+
filter:{EmbossFilter()},
717+
listName:"Emboss",
718+
titleName:"Emboss",
719+
sliderConfiguration:.enabled(minimumValue:0.0, maximumValue:5.0, initialValue:1.0),
720+
sliderUpdateCallback: {(filter, sliderValue) in
721+
filter.intensity = sliderValue
722+
},
723+
filterOperationType:.singleInput
724+
),
725725
FilterOperation(
726726
filter:{Laplacian()},
727727
listName:"Laplacian",
@@ -762,14 +762,14 @@ let filterOperations: Array<FilterOperationInterface> = [
762762
// },
763763
// filterOperationType:.singleInput
764764
// ),
765-
// FilterOperation(
766-
// filter:{KuwaharaRadius3Filter()},
767-
// listName:"Kuwahara (radius 3)",
768-
// titleName:"Kuwahara (Radius 3)",
769-
// sliderConfiguration:.disabled,
770-
// sliderUpdateCallback: nil,
771-
// filterOperationType:.singleInput
772-
// ),
765+
FilterOperation(
766+
filter:{KuwaharaRadius3Filter()},
767+
listName:"Kuwahara (radius 3)",
768+
titleName:"Kuwahara (Radius 3)",
769+
sliderConfiguration:.disabled,
770+
sliderUpdateCallback: nil,
771+
filterOperationType:.singleInput
772+
),
773773
FilterOperation(
774774
filter:{Vignette()},
775775
listName:"Vignette",

framework/GPUImage.xcodeproj/project.pbxproj

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,16 @@
149149
795ECACA21EF9806000EF927 /* ColorLocalBinaryPattern.metal in Sources */ = {isa = PBXBuildFile; fileRef = 795ECAC821EF9806000EF927 /* ColorLocalBinaryPattern.metal */; };
150150
795ECACC21F02E54000EF927 /* PolkaDot.metal in Sources */ = {isa = PBXBuildFile; fileRef = 79DD50D2213458BA004EF308 /* PolkaDot.metal */; };
151151
795ECACD21F02E54000EF927 /* PolkaDot.metal in Sources */ = {isa = PBXBuildFile; fileRef = 79DD50D2213458BA004EF308 /* PolkaDot.metal */; };
152+
7999997A2226EA4A007404F2 /* EmbossFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799999792226EA4A007404F2 /* EmbossFilter.swift */; };
153+
7999997B2226EA4A007404F2 /* EmbossFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799999792226EA4A007404F2 /* EmbossFilter.swift */; };
154+
7999997D2226EC05007404F2 /* KuwaharaFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7999997C2226EC05007404F2 /* KuwaharaFilter.swift */; };
155+
7999997E2226EC05007404F2 /* KuwaharaFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7999997C2226EC05007404F2 /* KuwaharaFilter.swift */; };
156+
799999802226EC17007404F2 /* KuwaharaFilter.metal in Sources */ = {isa = PBXBuildFile; fileRef = 7999997F2226EC17007404F2 /* KuwaharaFilter.metal */; };
157+
799999812226EC17007404F2 /* KuwaharaFilter.metal in Sources */ = {isa = PBXBuildFile; fileRef = 7999997F2226EC17007404F2 /* KuwaharaFilter.metal */; };
158+
799999832226FE8F007404F2 /* KuwaharaRadius3Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799999822226FE8F007404F2 /* KuwaharaRadius3Filter.swift */; };
159+
799999842226FE8F007404F2 /* KuwaharaRadius3Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799999822226FE8F007404F2 /* KuwaharaRadius3Filter.swift */; };
160+
799999862226FE9A007404F2 /* KuwaharaRadius3Filter.metal in Sources */ = {isa = PBXBuildFile; fileRef = 799999852226FE9A007404F2 /* KuwaharaRadius3Filter.metal */; };
161+
799999872226FE9A007404F2 /* KuwaharaRadius3Filter.metal in Sources */ = {isa = PBXBuildFile; fileRef = 799999852226FE9A007404F2 /* KuwaharaRadius3Filter.metal */; };
152162
79A81C882100E1B700A3B43A /* LevelsAdjustment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79A81C872100E1B700A3B43A /* LevelsAdjustment.swift */; };
153163
79A81C892100E1B700A3B43A /* LevelsAdjustment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79A81C872100E1B700A3B43A /* LevelsAdjustment.swift */; };
154164
79A81C8B2100E1C500A3B43A /* LevelsAdjustment.metal in Sources */ = {isa = PBXBuildFile; fileRef = 79A81C8A2100E1C500A3B43A /* LevelsAdjustment.metal */; };
@@ -425,6 +435,11 @@
425435
795ECAC221EF961F000EF927 /* LocalBinaryPattern.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; name = LocalBinaryPattern.metal; path = Source/Operations/LocalBinaryPattern.metal; sourceTree = "<group>"; };
426436
795ECAC521EF97F8000EF927 /* ColorLocalBinaryPattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorLocalBinaryPattern.swift; path = Source/Operations/ColorLocalBinaryPattern.swift; sourceTree = "<group>"; };
427437
795ECAC821EF9806000EF927 /* ColorLocalBinaryPattern.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; name = ColorLocalBinaryPattern.metal; path = Source/Operations/ColorLocalBinaryPattern.metal; sourceTree = "<group>"; };
438+
799999792226EA4A007404F2 /* EmbossFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = EmbossFilter.swift; path = Source/Operations/EmbossFilter.swift; sourceTree = "<group>"; };
439+
7999997C2226EC05007404F2 /* KuwaharaFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = KuwaharaFilter.swift; path = Source/Operations/KuwaharaFilter.swift; sourceTree = "<group>"; };
440+
7999997F2226EC17007404F2 /* KuwaharaFilter.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; name = KuwaharaFilter.metal; path = Source/Operations/KuwaharaFilter.metal; sourceTree = "<group>"; };
441+
799999822226FE8F007404F2 /* KuwaharaRadius3Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = KuwaharaRadius3Filter.swift; path = Source/Operations/KuwaharaRadius3Filter.swift; sourceTree = "<group>"; };
442+
799999852226FE9A007404F2 /* KuwaharaRadius3Filter.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; name = KuwaharaRadius3Filter.metal; path = Source/Operations/KuwaharaRadius3Filter.metal; sourceTree = "<group>"; };
428443
79A81C872100E1B700A3B43A /* LevelsAdjustment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LevelsAdjustment.swift; path = Source/Operations/LevelsAdjustment.swift; sourceTree = "<group>"; };
429444
79A81C8A2100E1C500A3B43A /* LevelsAdjustment.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; name = LevelsAdjustment.metal; path = Source/Operations/LevelsAdjustment.metal; sourceTree = "<group>"; };
430445
79A81C8D2100F0E300A3B43A /* OpacityAdjustment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OpacityAdjustment.swift; path = Source/Operations/OpacityAdjustment.swift; sourceTree = "<group>"; };
@@ -597,6 +612,11 @@
597612
7954BF542214C0EA008402A6 /* GlassSphere.metal */,
598613
7954BF572214C879008402A6 /* MotionBlur.swift */,
599614
7954BF5A2214C884008402A6 /* MotionBlur.metal */,
615+
799999792226EA4A007404F2 /* EmbossFilter.swift */,
616+
7999997C2226EC05007404F2 /* KuwaharaFilter.swift */,
617+
7999997F2226EC17007404F2 /* KuwaharaFilter.metal */,
618+
799999822226FE8F007404F2 /* KuwaharaRadius3Filter.swift */,
619+
799999852226FE9A007404F2 /* KuwaharaRadius3Filter.metal */,
600620
);
601621
name = Effects;
602622
sourceTree = "<group>";
@@ -994,6 +1014,7 @@
9941014
79DD50C7213450CB004EF308 /* SwirlDistortion.metal in Sources */,
9951015
79E30E6620F10F72005FA13C /* BasicOperation.swift in Sources */,
9961016
BCE0BEA820D6E3C80006E120 /* ImageOrientation.swift in Sources */,
1017+
799999862226FE9A007404F2 /* KuwaharaRadius3Filter.metal in Sources */,
9971018
79CB6DD52108B4090042F87B /* ColorDodgeBlend.metal in Sources */,
9981019
79CB6DF02109270C0042F87B /* HardLightBlend.swift in Sources */,
9991020
7957437120FBED78001EAE0A /* RGBAdjustment.metal in Sources */,
@@ -1029,6 +1050,7 @@
10291050
795ECAAB21ED2975000EF927 /* Sketch.metal in Sources */,
10301051
793D933220F68A32008A7A6E /* ExposureAdjustment.metal in Sources */,
10311052
79CB6DED210926300042F87B /* ExclusionBlend.metal in Sources */,
1053+
7999997D2226EC05007404F2 /* KuwaharaFilter.swift in Sources */,
10321054
795ECA7721E903F1000EF927 /* Toon.metal in Sources */,
10331055
7957437520FBF453001EAE0A /* Haze.swift in Sources */,
10341056
79CB6E0B21092E3E0042F87B /* LuminosityBlend.metal in Sources */,
@@ -1091,6 +1113,7 @@
10911113
79E30E6320F10B6C005FA13C /* MetalRenderingDevice.swift in Sources */,
10921114
7B25C0E62103D334000EC621 /* AlphaBlend.metal in Sources */,
10931115
795ECA8321E91434000EF927 /* Crosshatch.metal in Sources */,
1116+
799999802226EC17007404F2 /* KuwaharaFilter.metal in Sources */,
10941117
7954BF4022148C7D008402A6 /* HalfTone.swift in Sources */,
10951118
BC5193B12208F2CA00DD18F6 /* Pixellate.swift in Sources */,
10961119
793D932C20F66C66008A7A6E /* ColorInversion.metal in Sources */,
@@ -1119,6 +1142,7 @@
11191142
7954BF3D221485DE008402A6 /* PolkaDot.swift in Sources */,
11201143
79CB6E32210A0D8D0042F87B /* SoftLightBlend.metal in Sources */,
11211144
7957437B20FE2A6C001EAE0A /* LuminanceThreshold.swift in Sources */,
1145+
7999997A2226EA4A007404F2 /* EmbossFilter.swift in Sources */,
11221146
7957438120FE2D97001EAE0A /* FalseColor.swift in Sources */,
11231147
795ECAA221ED253B000EF927 /* ThresholdSobelEdgeDetection.swift in Sources */,
11241148
79CB6E41210A53CA0042F87B /* BlendShaderTypes.metal in Sources */,
@@ -1132,6 +1156,7 @@
11321156
79A81C912100F0EE00A3B43A /* OpacityAdjustment.metal in Sources */,
11331157
795ECA7421E903E2000EF927 /* Toon.swift in Sources */,
11341158
795ECAC021EF95EB000EF927 /* LocalBinaryPattern.swift in Sources */,
1159+
799999832226FE8F007404F2 /* KuwaharaRadius3Filter.swift in Sources */,
11351160
79CB6DE42108CC460042F87B /* DivideBlend.swift in Sources */,
11361161
BCE0BEA420D6E3C80006E120 /* Pipeline.swift in Sources */,
11371162
);
@@ -1170,6 +1195,7 @@
11701195
793D932620F66303008A7A6E /* Luminance.metal in Sources */,
11711196
BC67D91820F815B60046D2C4 /* RenderView.swift in Sources */,
11721197
79CB6DD62108B4090042F87B /* ColorDodgeBlend.metal in Sources */,
1198+
799999872226FE9A007404F2 /* KuwaharaRadius3Filter.metal in Sources */,
11731199
79CB6DF12109270C0042F87B /* HardLightBlend.swift in Sources */,
11741200
793D934520F693B8008A7A6E /* GammaAdjustment.metal in Sources */,
11751201
BCC6AB60210E5E7900F9803A /* TextureSamplingOperation.swift in Sources */,
@@ -1205,6 +1231,7 @@
12051231
795ECAAC21ED2975000EF927 /* Sketch.metal in Sources */,
12061232
7957437620FBF453001EAE0A /* Haze.swift in Sources */,
12071233
79CB6DEE210926300042F87B /* ExclusionBlend.metal in Sources */,
1234+
7999997E2226EC05007404F2 /* KuwaharaFilter.swift in Sources */,
12081235
795ECA7821E903F1000EF927 /* Toon.metal in Sources */,
12091236
BCFCD46820FCE91200560BC9 /* DissolveBlend.metal in Sources */,
12101237
79CB6E0C21092E3E0042F87B /* LuminosityBlend.metal in Sources */,
@@ -1267,6 +1294,7 @@
12671294
793D933020F68A21008A7A6E /* ExposureAdjustment.swift in Sources */,
12681295
793D934820F69A7F008A7A6E /* HueAdjustment.swift in Sources */,
12691296
7B25C0E72103D334000EC621 /* AlphaBlend.metal in Sources */,
1297+
799999812226EC17007404F2 /* KuwaharaFilter.metal in Sources */,
12701298
795ECA8421E91434000EF927 /* Crosshatch.metal in Sources */,
12711299
7954BF4122148C7D008402A6 /* HalfTone.swift in Sources */,
12721300
BC5193B22208F2CA00DD18F6 /* Pixellate.swift in Sources */,
@@ -1295,6 +1323,7 @@
12951323
7954BF3E221485DE008402A6 /* PolkaDot.swift in Sources */,
12961324
79CB6E33210A0D8D0042F87B /* SoftLightBlend.metal in Sources */,
12971325
7957438220FE2D97001EAE0A /* FalseColor.swift in Sources */,
1326+
7999997B2226EA4A007404F2 /* EmbossFilter.swift in Sources */,
12981327
7957437220FBED78001EAE0A /* RGBAdjustment.metal in Sources */,
12991328
795ECAA321ED253B000EF927 /* ThresholdSobelEdgeDetection.swift in Sources */,
13001329
79CB6E42210A53CA0042F87B /* BlendShaderTypes.metal in Sources */,
@@ -1308,6 +1337,7 @@
13081337
79A81C922100F0EE00A3B43A /* OpacityAdjustment.metal in Sources */,
13091338
795ECA7521E903E2000EF927 /* Toon.swift in Sources */,
13101339
795ECAC121EF95EB000EF927 /* LocalBinaryPattern.swift in Sources */,
1340+
799999842226FE8F007404F2 /* KuwaharaRadius3Filter.swift in Sources */,
13111341
79CB6DE52108CC460042F87B /* DivideBlend.swift in Sources */,
13121342
BCE0BEA520D6E3C80006E120 /* Pipeline.swift in Sources */,
13131343
);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
public class EmbossFilter : Convolution3x3 {
2+
public var intensity:Float = 1.0 {
3+
didSet {
4+
self.convolutionKernel = Matrix3x3(rowMajorValues:[
5+
intensity * (-2.0), -intensity, 0.0,
6+
-intensity, 1.0, intensity,
7+
0.0, intensity, intensity * 2.0])
8+
}
9+
}
10+
11+
public override init() {
12+
super.init()
13+
14+
({intensity = 1.0})()
15+
}
16+
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// Sourced from Kyprianidis, J. E., Kang, H., and Doellner, J. "Anisotropic Kuwahara Filtering on the GPU," GPU Pro p.247 (2010).
2+
//
3+
// Original header:
4+
//
5+
// Anisotropic Kuwahara Filtering on the GPU
6+
// by Jan Eric Kyprianidis <www.kyprianidis.com>
7+
8+
#include <metal_stdlib>
9+
#include "OperationShaderTypes.h"
10+
using namespace metal;
11+
12+
typedef struct {
13+
float radius;
14+
} KuwaharaUniform;
15+
16+
constant float2 src_size = float2(1.0 / 768.0, 1.0 / 1024.0);
17+
18+
fragment half4 kuwaharaFragment(SingleInputVertexIO fragmentInput [[stage_in]],
19+
texture2d<half> inputTexture [[texture(0)]],
20+
constant KuwaharaUniform& uniform [[buffer(1)]])
21+
{
22+
constexpr sampler quadSampler;
23+
float2 textureCoordinateToUse = fragmentInput.textureCoordinate;
24+
float n = float((uniform.radius + 1.0) * (uniform.radius + 1.0));
25+
26+
int i;
27+
int j;
28+
29+
float3 m0 = float3(0.0);
30+
float3 m1 = float3(0.0);
31+
float3 m2 = float3(0.0);
32+
float3 m3 = float3(0.0);
33+
34+
float3 s0 = float3(0.0);
35+
float3 s1 = float3(0.0);
36+
float3 s2 = float3(0.0);
37+
float3 s3 = float3(0.0);
38+
39+
float3 c;
40+
41+
for (j = -float(uniform.radius); j <= 0; ++j) {
42+
for (i = -float(uniform.radius); i <= 0; ++i) {
43+
c = float3(inputTexture.sample(quadSampler, textureCoordinateToUse + float2(float(i),float(j)) * src_size).rgb);
44+
m0 += c;
45+
s0 += c * c;
46+
}
47+
}
48+
49+
for (j = -float(uniform.radius); j <= 0; ++j) {
50+
for (i = 0; i <= -float(uniform.radius); ++i) {
51+
c = float3(inputTexture.sample(quadSampler, textureCoordinateToUse + float2(float(i),float(j)) * src_size).rgb);
52+
m1 += c;
53+
s1 += c * c;
54+
}
55+
}
56+
57+
for (j = 0; j <= float(uniform.radius); ++j) {
58+
for (i = 0; i <= float(uniform.radius); ++i) {
59+
c = float3(inputTexture.sample(quadSampler, textureCoordinateToUse + float2(float(i),float(j)) * src_size).rgb);
60+
m2 += c;
61+
s2 += c * c;
62+
}
63+
}
64+
65+
for (j = 0; j <= float(uniform.radius); ++j) {
66+
for (i = -float(uniform.radius); i <= 0; ++i) {
67+
c = float3(inputTexture.sample(quadSampler, textureCoordinateToUse + float2(float(i),float(j)) * src_size).rgb);
68+
m3 += c;
69+
s3 += c * c;
70+
}
71+
}
72+
73+
float min_sigma2 = 100;
74+
m0 /= n;
75+
s0 = abs(s0 / n - m0 * m0);
76+
77+
float sigma2 = s0.r + s0.g + s0.b;
78+
79+
if (sigma2 < min_sigma2) {
80+
min_sigma2 = sigma2;
81+
return half4(half3(m0), 1.0);
82+
}
83+
84+
m1 /= n;
85+
s1 = abs(s1 / n - m1 * m1);
86+
87+
sigma2 = s1.r + s1.g + s1.b;
88+
if (sigma2 < min_sigma2) {
89+
min_sigma2 = sigma2;
90+
return half4(half3(m1), 1.0);
91+
}
92+
93+
m2 /= n;
94+
s2 = abs(s2 / n - m2 * m2);
95+
96+
sigma2 = s2.r + s2.g + s2.b;
97+
if (sigma2 < min_sigma2) {
98+
min_sigma2 = sigma2;
99+
return half4(half3(m2), 1.0);
100+
}
101+
102+
m3 /= n;
103+
s3 = abs(s3 / n - m3 * m3);
104+
105+
sigma2 = s3.r + s3.g + s3.b;
106+
if (sigma2 < min_sigma2) {
107+
min_sigma2 = sigma2;
108+
return half4(half3(m3), 1.0);
109+
}
110+
}
111+
112+
/*
113+
varying vec2 textureCoordinate;
114+
uniform sampler2D inputImageTexture;
115+
uniform int radius;
116+
117+
const vec2 src_size = vec2 (1.0 / 768.0, 1.0 / 1024.0);
118+
119+
void main (void)
120+
{
121+
vec2 uv = textureCoordinate;
122+
float n = float((radius + 1) * (radius + 1));
123+
int i; int j;
124+
vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);
125+
vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);
126+
vec3 c;
127+
128+
for (j = -radius; j <= 0; ++j) {
129+
for (i = -radius; i <= 0; ++i) {
130+
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
131+
m0 += c;
132+
s0 += c * c;
133+
}
134+
}
135+
136+
for (j = -radius; j <= 0; ++j) {
137+
for (i = 0; i <= radius; ++i) {
138+
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
139+
m1 += c;
140+
s1 += c * c;
141+
}
142+
}
143+
144+
for (j = 0; j <= radius; ++j) {
145+
for (i = 0; i <= radius; ++i) {
146+
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
147+
m2 += c;
148+
s2 += c * c;
149+
}
150+
}
151+
152+
for (j = 0; j <= radius; ++j) {
153+
for (i = -radius; i <= 0; ++i) {
154+
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
155+
m3 += c;
156+
s3 += c * c;
157+
}
158+
}
159+
160+
161+
float min_sigma2 = 1e+2;
162+
m0 /= n;
163+
s0 = abs(s0 / n - m0 * m0);
164+
165+
float sigma2 = s0.r + s0.g + s0.b;
166+
if (sigma2 < min_sigma2) {
167+
min_sigma2 = sigma2;
168+
gl_FragColor = vec4(m0, 1.0);
169+
}
170+
171+
m1 /= n;
172+
s1 = abs(s1 / n - m1 * m1);
173+
174+
sigma2 = s1.r + s1.g + s1.b;
175+
if (sigma2 < min_sigma2) {
176+
min_sigma2 = sigma2;
177+
gl_FragColor = vec4(m1, 1.0);
178+
}
179+
180+
m2 /= n;
181+
s2 = abs(s2 / n - m2 * m2);
182+
183+
sigma2 = s2.r + s2.g + s2.b;
184+
if (sigma2 < min_sigma2) {
185+
min_sigma2 = sigma2;
186+
gl_FragColor = vec4(m2, 1.0);
187+
}
188+
189+
m3 /= n;
190+
s3 = abs(s3 / n - m3 * m3);
191+
192+
sigma2 = s3.r + s3.g + s3.b;
193+
if (sigma2 < min_sigma2) {
194+
min_sigma2 = sigma2;
195+
gl_FragColor = vec4(m3, 1.0);
196+
}
197+
}
198+
*/
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
public class KuwaharaFilter: BasicOperation {
2+
public var radius:Float = 3.0 { didSet { uniformSettings["radius"] = radius } }
3+
4+
public init() {
5+
super.init(fragmentFunctionName:"kuwaharaFragment", numberOfInputs:1)
6+
7+
({radius = 3.0})()
8+
}
9+
}

0 commit comments

Comments
 (0)