diff --git a/README.md b/README.md index 98a824a3..34715e99 100755 --- a/README.md +++ b/README.md @@ -432,6 +432,9 @@ There are currently over 100 operations built into the framework, divided into t - **HistogramDisplay**: This is a special filter, in that it's primarily intended to work with the Histogram. It generates an output representation of the color histograms generated by Histogram, but it could be repurposed to display other kinds of values. It takes in an image and looks at the center (vertical) pixels. It then plots the numerical values of the RGB components in separate colored graphs in an output texture. You may need to force a size for this filter in order to make its output visible. +- **HistogramEqualization**: This takes a image, analyzes its histogram, and equalizes the outbound image based on that. + - *downsamplingFactor*: Rather than sampling every pixel, this dictates what fraction of the image is sampled by the histogram. By default, this is 16 with a minimum of 1. This is needed to keep from saturating the histogram, which can only record 256 pixels for each color value before it becomes overloaded. + - **CannyEdgeDetection**: This uses the full Canny process to highlight one-pixel-wide edges - *blurRadiusInPixels*: The underlying blur radius for the Gaussian blur. Default is 2.0. - *upperThreshold*: Any edge with a gradient magnitude above this threshold will pass and show up in the final result. Default is 0.4. diff --git a/examples/Mac/FilterShowcase/FilterShowcase/FilterOperations.swift b/examples/Mac/FilterShowcase/FilterShowcase/FilterOperations.swift index 31f04931..94d212de 100755 --- a/examples/Mac/FilterShowcase/FilterShowcase/FilterOperations.swift +++ b/examples/Mac/FilterShowcase/FilterShowcase/FilterOperations.swift @@ -311,6 +311,14 @@ let filterOperations: Array = [ return blendFilter }) ), + FilterOperation ( + filter:{HistogramEqualization(type:.RGB)}, + listName:"Histogram equalization", + titleName:"Histogram Equalization", + sliderConfiguration:.Disabled, + sliderUpdateCallback:nil, + filterOperationType:.SingleInput + ), FilterOperation( filter:{AverageColorExtractor()}, listName:"Average color", diff --git a/framework/GPUImage-Mac.xcodeproj/project.pbxproj b/framework/GPUImage-Mac.xcodeproj/project.pbxproj index 3df11547..3f650acb 100755 --- a/framework/GPUImage-Mac.xcodeproj/project.pbxproj +++ b/framework/GPUImage-Mac.xcodeproj/project.pbxproj @@ -144,6 +144,7 @@ BCB825B61CC9C1F100339790 /* MovieOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB825B51CC9C1F100339790 /* MovieOutput.swift */; }; BCB825BB1CC9C96B00339790 /* Timestamp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB825BA1CC9C96B00339790 /* Timestamp.swift */; }; BCBEC0C61CCD2E6200B70ED7 /* Histogram.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCBEC0C51CCD2E6200B70ED7 /* Histogram.swift */; }; + BCBEC0E01CCD492D00B70ED7 /* HistogramEqualization.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCBEC0DF1CCD492D00B70ED7 /* HistogramEqualization.swift */; }; BCD1B14A1C66AE00001F2BDC /* SerialDispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD1B1491C66AE00001F2BDC /* SerialDispatch.swift */; }; BCD1B14C1C66B225001F2BDC /* Pipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD1B14B1C66B225001F2BDC /* Pipeline.swift */; }; BCE111A51CBC94FD005293A4 /* AverageLuminanceExtractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE111A41CBC94FD005293A4 /* AverageLuminanceExtractor.swift */; }; @@ -410,6 +411,12 @@ BCBEC0C91CCD2E8900B70ED7 /* HistogramGreenSampling.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramGreenSampling.vsh; path = Source/Operations/Shaders/HistogramGreenSampling.vsh; sourceTree = ""; }; BCBEC0CA1CCD2E8900B70ED7 /* HistogramLuminanceSampling.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramLuminanceSampling.vsh; path = Source/Operations/Shaders/HistogramLuminanceSampling.vsh; sourceTree = ""; }; BCBEC0CB1CCD2E8900B70ED7 /* HistogramRedSampling.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramRedSampling.vsh; path = Source/Operations/Shaders/HistogramRedSampling.vsh; sourceTree = ""; }; + BCBEC0DF1CCD492D00B70ED7 /* HistogramEqualization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HistogramEqualization.swift; path = Source/Operations/HistogramEqualization.swift; sourceTree = ""; }; + BCBEC0E11CCD496B00B70ED7 /* HistogramEqualizationBlue_GL.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationBlue_GL.fsh; path = Source/Operations/Shaders/HistogramEqualizationBlue_GL.fsh; sourceTree = ""; }; + BCBEC0E21CCD496B00B70ED7 /* HistogramEqualizationGreen_GL.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationGreen_GL.fsh; path = Source/Operations/Shaders/HistogramEqualizationGreen_GL.fsh; sourceTree = ""; }; + BCBEC0E31CCD496B00B70ED7 /* HistogramEqualizationLuminance_GL.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationLuminance_GL.fsh; path = Source/Operations/Shaders/HistogramEqualizationLuminance_GL.fsh; sourceTree = ""; }; + BCBEC0E41CCD496B00B70ED7 /* HistogramEqualizationRed_GL.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationRed_GL.fsh; path = Source/Operations/Shaders/HistogramEqualizationRed_GL.fsh; sourceTree = ""; }; + BCBEC0E51CCD496B00B70ED7 /* HistogramEqualizationRGB_GL.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationRGB_GL.fsh; path = Source/Operations/Shaders/HistogramEqualizationRGB_GL.fsh; sourceTree = ""; }; BCD1B1491C66AE00001F2BDC /* SerialDispatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SerialDispatch.swift; path = Source/SerialDispatch.swift; sourceTree = ""; }; BCD1B14B1C66B225001F2BDC /* Pipeline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Pipeline.swift; path = Source/Pipeline.swift; sourceTree = ""; }; BCE111A41CBC94FD005293A4 /* AverageLuminanceExtractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AverageLuminanceExtractor.swift; path = Source/Operations/AverageLuminanceExtractor.swift; sourceTree = ""; }; @@ -652,6 +659,12 @@ BC4EE1651CB34B3700AD8A65 /* HistogramDisplay.swift */, BC4EE1681CB34B8900AD8A65 /* HistogramDisplay.vsh */, BC4EE1671CB34B8900AD8A65 /* HistogramDisplay_GL.fsh */, + BCBEC0DF1CCD492D00B70ED7 /* HistogramEqualization.swift */, + BCBEC0E11CCD496B00B70ED7 /* HistogramEqualizationBlue_GL.fsh */, + BCBEC0E21CCD496B00B70ED7 /* HistogramEqualizationGreen_GL.fsh */, + BCBEC0E31CCD496B00B70ED7 /* HistogramEqualizationLuminance_GL.fsh */, + BCBEC0E41CCD496B00B70ED7 /* HistogramEqualizationRed_GL.fsh */, + BCBEC0E51CCD496B00B70ED7 /* HistogramEqualizationRGB_GL.fsh */, BC4EE1731CB3711600AD8A65 /* GaussianBlur.swift */, BCFF46E11CBADB3E00A0C521 /* SingleComponentGaussianBlur.swift */, BC8B7A8E1CB5A84C00ACF7AA /* BoxBlur.swift */, @@ -1111,6 +1124,7 @@ BC77295C1CB30CD2004C9E0B /* TextureSamplingOperation.swift in Sources */, BC1E13291C9F6282008F844F /* PictureInput.swift in Sources */, BC7FD10E1CB0783500037949 /* ExclusionBlend.swift in Sources */, + BCBEC0E01CCD492D00B70ED7 /* HistogramEqualization.swift in Sources */, BC7FD0F91CB063B700037949 /* Color.swift in Sources */, BCFF46DF1CBAB66F00A0C521 /* CannyEdgeDetection.swift in Sources */, BCFF46BC1CB8AB1B00A0C521 /* TiltShift.swift in Sources */, diff --git a/framework/GPUImage-iOS.xcodeproj/project.pbxproj b/framework/GPUImage-iOS.xcodeproj/project.pbxproj index 2b8740d6..07abb0e8 100755 --- a/framework/GPUImage-iOS.xcodeproj/project.pbxproj +++ b/framework/GPUImage-iOS.xcodeproj/project.pbxproj @@ -32,6 +32,12 @@ BCB825BE1CC9CA6B00339790 /* Timestamp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB825BD1CC9CA6B00339790 /* Timestamp.swift */; }; BCB825C01CC9CA8100339790 /* MovieOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB825BF1CC9CA8100339790 /* MovieOutput.swift */; }; BCBEC0D21CCD404900B70ED7 /* Histogram.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCBEC0D11CCD404900B70ED7 /* Histogram.swift */; }; + BCBEC0EC1CCD499D00B70ED7 /* HistogramEqualization.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCBEC0EB1CCD499D00B70ED7 /* HistogramEqualization.swift */; }; + BCBEC0F21CCD49B800B70ED7 /* HistogramEqualizationBlue_GLES.fsh in Resources */ = {isa = PBXBuildFile; fileRef = BCBEC0ED1CCD49B800B70ED7 /* HistogramEqualizationBlue_GLES.fsh */; }; + BCBEC0F31CCD49B800B70ED7 /* HistogramEqualizationGreen_GLES.fsh in Resources */ = {isa = PBXBuildFile; fileRef = BCBEC0EE1CCD49B800B70ED7 /* HistogramEqualizationGreen_GLES.fsh */; }; + BCBEC0F41CCD49B800B70ED7 /* HistogramEqualizationLuminance_GLES.fsh in Resources */ = {isa = PBXBuildFile; fileRef = BCBEC0EF1CCD49B800B70ED7 /* HistogramEqualizationLuminance_GLES.fsh */; }; + BCBEC0F51CCD49B800B70ED7 /* HistogramEqualizationRed_GLES.fsh in Resources */ = {isa = PBXBuildFile; fileRef = BCBEC0F01CCD49B800B70ED7 /* HistogramEqualizationRed_GLES.fsh */; }; + BCBEC0F61CCD49B800B70ED7 /* HistogramEqualizationRGB_GLES.fsh in Resources */ = {isa = PBXBuildFile; fileRef = BCBEC0F11CCD49B800B70ED7 /* HistogramEqualizationRGB_GLES.fsh */; }; BCD03F0F1CA23D6300271751 /* Camera.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD03F0E1CA23D6300271751 /* Camera.swift */; }; BCD1B1301C66A262001F2BDC /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCD1B1251C66A262001F2BDC /* GPUImage.framework */; }; BCD1B1351C66A262001F2BDC /* GPUImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD1B1341C66A262001F2BDC /* GPUImageTests.swift */; }; @@ -210,6 +216,12 @@ BCBEC0D51CCD407500B70ED7 /* HistogramGreenSampling.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramGreenSampling.vsh; path = Source/Operations/Shaders/HistogramGreenSampling.vsh; sourceTree = ""; }; BCBEC0D61CCD407500B70ED7 /* HistogramLuminanceSampling.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramLuminanceSampling.vsh; path = Source/Operations/Shaders/HistogramLuminanceSampling.vsh; sourceTree = ""; }; BCBEC0D71CCD407500B70ED7 /* HistogramRedSampling.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramRedSampling.vsh; path = Source/Operations/Shaders/HistogramRedSampling.vsh; sourceTree = ""; }; + BCBEC0EB1CCD499D00B70ED7 /* HistogramEqualization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HistogramEqualization.swift; path = Source/Operations/HistogramEqualization.swift; sourceTree = ""; }; + BCBEC0ED1CCD49B800B70ED7 /* HistogramEqualizationBlue_GLES.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationBlue_GLES.fsh; path = Source/Operations/Shaders/HistogramEqualizationBlue_GLES.fsh; sourceTree = ""; }; + BCBEC0EE1CCD49B800B70ED7 /* HistogramEqualizationGreen_GLES.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationGreen_GLES.fsh; path = Source/Operations/Shaders/HistogramEqualizationGreen_GLES.fsh; sourceTree = ""; }; + BCBEC0EF1CCD49B800B70ED7 /* HistogramEqualizationLuminance_GLES.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationLuminance_GLES.fsh; path = Source/Operations/Shaders/HistogramEqualizationLuminance_GLES.fsh; sourceTree = ""; }; + BCBEC0F01CCD49B800B70ED7 /* HistogramEqualizationRed_GLES.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationRed_GLES.fsh; path = Source/Operations/Shaders/HistogramEqualizationRed_GLES.fsh; sourceTree = ""; }; + BCBEC0F11CCD49B800B70ED7 /* HistogramEqualizationRGB_GLES.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = HistogramEqualizationRGB_GLES.fsh; path = Source/Operations/Shaders/HistogramEqualizationRGB_GLES.fsh; sourceTree = ""; }; BCD03F0E1CA23D6300271751 /* Camera.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Camera.swift; path = Source/iOS/Camera.swift; sourceTree = ""; }; BCD1B1251C66A262001F2BDC /* GPUImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GPUImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BCD1B12F1C66A262001F2BDC /* GPUImageTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GPUImageTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -767,6 +779,12 @@ BCFB06B71CBF287C009B2333 /* HistogramDisplay.swift */, BCFB06E01CBF29F4009B2333 /* HistogramDisplay.vsh */, BCFB06DF1CBF29F4009B2333 /* HistogramDisplay_GLES.fsh */, + BCBEC0EB1CCD499D00B70ED7 /* HistogramEqualization.swift */, + BCBEC0ED1CCD49B800B70ED7 /* HistogramEqualizationBlue_GLES.fsh */, + BCBEC0EE1CCD49B800B70ED7 /* HistogramEqualizationGreen_GLES.fsh */, + BCBEC0EF1CCD49B800B70ED7 /* HistogramEqualizationLuminance_GLES.fsh */, + BCBEC0F01CCD49B800B70ED7 /* HistogramEqualizationRed_GLES.fsh */, + BCBEC0F11CCD49B800B70ED7 /* HistogramEqualizationRGB_GLES.fsh */, BCFB06931CBF284A009B2333 /* GaussianBlur.swift */, BCFB069F1CBF284A009B2333 /* SingleComponentGaussianBlur.swift */, BCFB06B91CBF2895009B2333 /* BoxBlur.swift */, @@ -974,6 +992,11 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + BCBEC0F21CCD49B800B70ED7 /* HistogramEqualizationBlue_GLES.fsh in Resources */, + BCBEC0F31CCD49B800B70ED7 /* HistogramEqualizationGreen_GLES.fsh in Resources */, + BCBEC0F61CCD49B800B70ED7 /* HistogramEqualizationRGB_GLES.fsh in Resources */, + BCBEC0F41CCD49B800B70ED7 /* HistogramEqualizationLuminance_GLES.fsh in Resources */, + BCBEC0F51CCD49B800B70ED7 /* HistogramEqualizationRed_GLES.fsh in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1092,6 +1115,7 @@ BCD03F0F1CA23D6300271751 /* Camera.swift in Sources */, BCFB05FD1CBF1FF8009B2333 /* DarkenBlend.swift in Sources */, BC6A13AF1CBB52F000387779 /* SaturationAdjustment.swift in Sources */, + BCBEC0EC1CCD499D00B70ED7 /* HistogramEqualization.swift in Sources */, BCFB07471CBF2BC1009B2333 /* SwirlDistortion.swift in Sources */, BCFB060A1CBF1FF8009B2333 /* SoftLightBlend.swift in Sources */, BCFB06091CBF1FF8009B2333 /* ScreenBlend.swift in Sources */, diff --git a/framework/Source/Framebuffer.swift b/framework/Source/Framebuffer.swift index dfba925c..bd54231e 100755 --- a/framework/Source/Framebuffer.swift +++ b/framework/Source/Framebuffer.swift @@ -93,7 +93,7 @@ public class Framebuffer { if (!textureOverride) { var mutableTexture = texture glDeleteTextures(1, &mutableTexture) - print("Delete texture") + print("Delete texture at size: \(size)") } if let framebuffer = framebuffer { diff --git a/framework/Source/Operations/Histogram.swift b/framework/Source/Operations/Histogram.swift index 1512befd..16f66f64 100644 --- a/framework/Source/Operations/Histogram.swift +++ b/framework/Source/Operations/Histogram.swift @@ -15,6 +15,17 @@ let GL_FALSE = GLboolean(0) #endif #endif +/* Unlike other filters, this one uses a grid of GL_POINTs to sample the incoming image in a grid. A custom vertex shader reads the color in the texture at its position + and outputs a bin position in the final histogram as the vertex position. That point is then written into the image of the histogram using translucent pixels. + The degree of translucency is controlled by the scalingFactor, which lets you adjust the dynamic range of the histogram. The histogram can only be generated for one + color channel or luminance value at a time. + + This is based on this implementation: http://www.shaderwrangler.com/publications/histogram/histogram_cameraready.pdf + + Or at least that's how it would work if iOS could read from textures in a vertex shader, which it can't. Therefore, I read the texture data down from the + incoming frame and process the texture colors as vertices. +*/ + public enum HistogramType { case Red case Blue diff --git a/framework/Source/Operations/HistogramEqualization.swift b/framework/Source/Operations/HistogramEqualization.swift new file mode 100644 index 00000000..c861d688 --- /dev/null +++ b/framework/Source/Operations/HistogramEqualization.swift @@ -0,0 +1,57 @@ +public class HistogramEqualization: OperationGroup { + public var downsamplingFactor: UInt = 16 { didSet { histogram.downsamplingFactor = downsamplingFactor } } + + let histogram:Histogram + let rawDataInput = RawDataInput() + let rawDataOutput = RawDataOutput() + let equalizationFilter:BasicOperation + + public init(type:HistogramType) { + + self.histogram = Histogram(type:type) + switch type { + case .Red: self.equalizationFilter = BasicOperation(fragmentShader:HistogramEqualizationRedFragmentShader, numberOfInputs:2) + case .Blue: self.equalizationFilter = BasicOperation(fragmentShader:HistogramEqualizationBlueFragmentShader, numberOfInputs:2) + case .Green: self.equalizationFilter = BasicOperation(fragmentShader:HistogramEqualizationGreenFragmentShader, numberOfInputs:2) + case .Luminance: self.equalizationFilter = BasicOperation(fragmentShader:HistogramEqualizationLuminanceFragmentShader, numberOfInputs:2) + case .RGB: self.equalizationFilter = BasicOperation(fragmentShader:HistogramEqualizationRGBFragmentShader, numberOfInputs:2) + } + + super.init() + + ({downsamplingFactor = 16})() + + self.configureGroup{input, output in + self.rawDataOutput.dataAvailableCallback = {data in + var redHistogramBin = [Int](count:256, repeatedValue:0) + var greenHistogramBin = [Int](count:256, repeatedValue:0) + var blueHistogramBin = [Int](count:256, repeatedValue:0) + + let rowWidth = 256 * 4 + redHistogramBin[0] = Int(data[rowWidth]) + greenHistogramBin[1] = Int(data[rowWidth + 1]) + blueHistogramBin[2] = Int(data[rowWidth + 2]) + + for dataIndex in 1..<256 { + redHistogramBin[dataIndex] = redHistogramBin[dataIndex - 1] + Int(data[rowWidth + (dataIndex * 4)]) + greenHistogramBin[dataIndex] = greenHistogramBin[dataIndex - 1] + Int(data[rowWidth + (dataIndex * 4) + 1]) + blueHistogramBin[dataIndex] = blueHistogramBin[dataIndex - 1] + Int(data[rowWidth + (dataIndex * 4) + 2]) + } + + var equalizationLookupTable = [UInt8](count:256 * 4, repeatedValue:0) + for binIndex in 0..<256 { + equalizationLookupTable[binIndex * 4] = UInt8((((redHistogramBin[binIndex] - redHistogramBin[0]) * 255) / redHistogramBin[255])) + equalizationLookupTable[(binIndex * 4) + 1] = UInt8((((greenHistogramBin[binIndex] - greenHistogramBin[0]) * 255) / greenHistogramBin[255])) + equalizationLookupTable[(binIndex * 4) + 2] = UInt8((((blueHistogramBin[binIndex] - blueHistogramBin[0]) * 255) / blueHistogramBin[255])) + equalizationLookupTable[(binIndex * 4) + 3] = 255 + } + + self.rawDataInput.uploadBytes(equalizationLookupTable, size:Size(width:256, height:1), pixelFormat:.RGBA) + } + + input --> self.histogram --> self.rawDataOutput + input --> self.equalizationFilter --> output + self.rawDataInput --> self.equalizationFilter + } + } +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/ConvertedShaders_GL.swift b/framework/Source/Operations/Shaders/ConvertedShaders_GL.swift index 4aa2d103..03c1f318 100644 --- a/framework/Source/Operations/Shaders/ConvertedShaders_GL.swift +++ b/framework/Source/Operations/Shaders/ConvertedShaders_GL.swift @@ -63,6 +63,11 @@ public let HistogramAccumulationFragmentShader = "const float scalingFactor = 1. public let HistogramBlueSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n void main()\n {\n colorFactor = vec3(0.0, 0.0, 1.0);\n gl_Position = vec4(-1.0 + (position.z * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " public let HistogramDisplayVertexShader = "attribute vec4 position;\n attribute vec4 inputTextureCoordinate;\n \n varying vec2 textureCoordinate;\n varying float height;\n \n void main()\n {\n gl_Position = position;\n textureCoordinate = vec2(inputTextureCoordinate.x, 0.5);\n height = 1.0 - inputTextureCoordinate.y;\n }\n " public let HistogramDisplayFragmentShader = "varying vec2 textureCoordinate;\n varying float height;\n \n uniform sampler2D inputImageTexture;\n vec4 backgroundColor = vec4(0.0, 0.0, 0.0, 0.0);\n \n void main()\n {\n vec3 colorChannels = texture2D(inputImageTexture, textureCoordinate).rgb;\n vec4 heightTest = vec4(step(height, colorChannels), 1.0);\n gl_FragColor = mix(backgroundColor, heightTest, heightTest.r + heightTest.g + heightTest.b);\n }\n " +public let HistogramEqualizationBlueFragmentShader = "varying vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;\n \n gl_FragColor = vec4(textureColor.r, textureColor.g, blueCurveValue, textureColor.a);\n }\n " +public let HistogramEqualizationGreenFragmentShader = "varying vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;\n \n gl_FragColor = vec4(textureColor.r, greenCurveValue, textureColor.b, textureColor.a);\n }\n " +public let HistogramEqualizationLuminanceFragmentShader = "varying vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n \n void main()\n {\n vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n float luminance = dot(textureColor.rgb, W);\n float newLuminance = texture2D(inputImageTexture2, vec2(luminance, 0.0)).r;\n float deltaLuminance = newLuminance - luminance;\n \n float red = clamp(textureColor.r + deltaLuminance, 0.0, 1.0);\n float green = clamp(textureColor.g + deltaLuminance, 0.0, 1.0);\n float blue = clamp(textureColor.b + deltaLuminance, 0.0, 1.0);\n \n gl_FragColor = vec4(red, green, blue, textureColor.a);\n }\n " +public let HistogramEqualizationRGBFragmentShader = "varying vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;\n float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;\n float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;\n \n gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);\n }\n " +public let HistogramEqualizationRedFragmentShader = "varying vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;\n \n gl_FragColor = vec4(redCurveValue, textureColor.g, textureColor.b, textureColor.a);\n }\n " public let HistogramGreenSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n void main()\n {\n colorFactor = vec3(0.0, 1.0, 0.0);\n gl_Position = vec4(-1.0 + (position.y * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " public let HistogramLuminanceSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n \n void main()\n {\n float luminance = dot(position.xyz, W);\n \n colorFactor = vec3(1.0, 1.0, 1.0);\n gl_Position = vec4(-1.0 + (luminance * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " public let HistogramRedSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n void main()\n {\n colorFactor = vec3(1.0, 0.0, 0.0);\n gl_Position = vec4(-1.0 + (position.x * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " diff --git a/framework/Source/Operations/Shaders/ConvertedShaders_GLES.swift b/framework/Source/Operations/Shaders/ConvertedShaders_GLES.swift index c7f76b52..f6e1974a 100644 --- a/framework/Source/Operations/Shaders/ConvertedShaders_GLES.swift +++ b/framework/Source/Operations/Shaders/ConvertedShaders_GLES.swift @@ -63,6 +63,11 @@ public let HistogramAccumulationFragmentShader = "const lowp float scalingFactor public let HistogramBlueSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n void main()\n {\n colorFactor = vec3(0.0, 0.0, 1.0);\n gl_Position = vec4(-1.0 + (position.z * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " public let HistogramDisplayVertexShader = "attribute vec4 position;\n attribute vec4 inputTextureCoordinate;\n \n varying vec2 textureCoordinate;\n varying float height;\n \n void main()\n {\n gl_Position = position;\n textureCoordinate = vec2(inputTextureCoordinate.x, 0.5);\n height = 1.0 - inputTextureCoordinate.y;\n }\n " public let HistogramDisplayFragmentShader = "varying highp vec2 textureCoordinate;\n varying highp float height;\n \n uniform sampler2D inputImageTexture;\n lowp vec4 backgroundColor = vec4(0.0, 0.0, 0.0, 0.0);\n \n void main()\n {\n lowp vec3 colorChannels = texture2D(inputImageTexture, textureCoordinate).rgb;\n lowp vec4 heightTest = vec4(step(height, colorChannels), 1.0);\n gl_FragColor = mix(backgroundColor, heightTest, heightTest.r + heightTest.g + heightTest.b);\n }\n " +public let HistogramEqualizationBlueFragmentShader = "varying highp vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n lowp float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;\n \n gl_FragColor = vec4(textureColor.r, textureColor.g, blueCurveValue, textureColor.a);\n }\n " +public let HistogramEqualizationGreenFragmentShader = "varying highp vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n lowp float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;\n \n gl_FragColor = vec4(textureColor.r, greenCurveValue, textureColor.b, textureColor.a);\n }\n " +public let HistogramEqualizationLuminanceFragmentShader = "varying highp vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n const lowp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n \n void main()\n {\n lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n lowp float luminance = dot(textureColor.rgb, W);\n lowp float newLuminance = texture2D(inputImageTexture2, vec2(luminance, 0.0)).r;\n lowp float deltaLuminance = newLuminance - luminance;\n \n lowp float red = clamp(textureColor.r + deltaLuminance, 0.0, 1.0);\n lowp float green = clamp(textureColor.g + deltaLuminance, 0.0, 1.0);\n lowp float blue = clamp(textureColor.b + deltaLuminance, 0.0, 1.0);\n \n gl_FragColor = vec4(red, green, blue, textureColor.a);\n }\n " +public let HistogramEqualizationRGBFragmentShader = "varying highp vec2 textureCoordinate; \n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n lowp float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;\n lowp float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;\n lowp float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;\n \n gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);\n }\n " +public let HistogramEqualizationRedFragmentShader = "varying highp vec2 textureCoordinate;\n uniform sampler2D inputImageTexture;\n uniform sampler2D inputImageTexture2;\n \n void main()\n {\n lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n lowp float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;\n \n gl_FragColor = vec4(redCurveValue, textureColor.g, textureColor.b, textureColor.a);\n }\n " public let HistogramGreenSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n void main()\n {\n colorFactor = vec3(0.0, 1.0, 0.0);\n gl_Position = vec4(-1.0 + (position.y * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " public let HistogramLuminanceSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n \n void main()\n {\n float luminance = dot(position.xyz, W);\n \n colorFactor = vec3(1.0, 1.0, 1.0);\n gl_Position = vec4(-1.0 + (luminance * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " public let HistogramRedSamplingVertexShader = "attribute vec4 position;\n \n varying vec3 colorFactor;\n \n void main()\n {\n colorFactor = vec3(1.0, 0.0, 0.0);\n gl_Position = vec4(-1.0 + (position.x * 0.0078125), 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n }\n " diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationBlue_GL.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationBlue_GL.fsh new file mode 100755 index 00000000..8d78d5df --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationBlue_GL.fsh @@ -0,0 +1,11 @@ +varying vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b; + + gl_FragColor = vec4(textureColor.r, textureColor.g, blueCurveValue, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationBlue_GLES.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationBlue_GLES.fsh new file mode 100755 index 00000000..4adca338 --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationBlue_GLES.fsh @@ -0,0 +1,11 @@ +varying highp vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + lowp float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b; + + gl_FragColor = vec4(textureColor.r, textureColor.g, blueCurveValue, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationGreen_GL.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationGreen_GL.fsh new file mode 100755 index 00000000..ae7dac9b --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationGreen_GL.fsh @@ -0,0 +1,11 @@ +varying vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g; + + gl_FragColor = vec4(textureColor.r, greenCurveValue, textureColor.b, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationGreen_GLES.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationGreen_GLES.fsh new file mode 100755 index 00000000..d847150e --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationGreen_GLES.fsh @@ -0,0 +1,11 @@ +varying highp vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + lowp float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g; + + gl_FragColor = vec4(textureColor.r, greenCurveValue, textureColor.b, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationLuminance_GL.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationLuminance_GL.fsh new file mode 100755 index 00000000..8bc37071 --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationLuminance_GL.fsh @@ -0,0 +1,19 @@ +varying vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +const vec3 W = vec3(0.2125, 0.7154, 0.0721); + +void main() +{ + vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + float luminance = dot(textureColor.rgb, W); + float newLuminance = texture2D(inputImageTexture2, vec2(luminance, 0.0)).r; + float deltaLuminance = newLuminance - luminance; + + float red = clamp(textureColor.r + deltaLuminance, 0.0, 1.0); + float green = clamp(textureColor.g + deltaLuminance, 0.0, 1.0); + float blue = clamp(textureColor.b + deltaLuminance, 0.0, 1.0); + + gl_FragColor = vec4(red, green, blue, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationLuminance_GLES.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationLuminance_GLES.fsh new file mode 100755 index 00000000..b7132311 --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationLuminance_GLES.fsh @@ -0,0 +1,19 @@ +varying highp vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +const lowp vec3 W = vec3(0.2125, 0.7154, 0.0721); + +void main() +{ + lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + lowp float luminance = dot(textureColor.rgb, W); + lowp float newLuminance = texture2D(inputImageTexture2, vec2(luminance, 0.0)).r; + lowp float deltaLuminance = newLuminance - luminance; + + lowp float red = clamp(textureColor.r + deltaLuminance, 0.0, 1.0); + lowp float green = clamp(textureColor.g + deltaLuminance, 0.0, 1.0); + lowp float blue = clamp(textureColor.b + deltaLuminance, 0.0, 1.0); + + gl_FragColor = vec4(red, green, blue, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationRGB_GL.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationRGB_GL.fsh new file mode 100755 index 00000000..3dd7bce6 --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationRGB_GL.fsh @@ -0,0 +1,13 @@ +varying vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r; + float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g; + float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b; + + gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationRGB_GLES.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationRGB_GLES.fsh new file mode 100755 index 00000000..5609780b --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationRGB_GLES.fsh @@ -0,0 +1,13 @@ +varying highp vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + lowp float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r; + lowp float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g; + lowp float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b; + + gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationRed_GL.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationRed_GL.fsh new file mode 100755 index 00000000..172063d2 --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationRed_GL.fsh @@ -0,0 +1,11 @@ +varying vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r; + + gl_FragColor = vec4(redCurveValue, textureColor.g, textureColor.b, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/Operations/Shaders/HistogramEqualizationRed_GLES.fsh b/framework/Source/Operations/Shaders/HistogramEqualizationRed_GLES.fsh new file mode 100755 index 00000000..f38af79f --- /dev/null +++ b/framework/Source/Operations/Shaders/HistogramEqualizationRed_GLES.fsh @@ -0,0 +1,11 @@ +varying highp vec2 textureCoordinate; +uniform sampler2D inputImageTexture; +uniform sampler2D inputImageTexture2; + +void main() +{ + lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); + lowp float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r; + + gl_FragColor = vec4(redCurveValue, textureColor.g, textureColor.b, textureColor.a); +} \ No newline at end of file diff --git a/framework/Source/RawDataInput.swift b/framework/Source/RawDataInput.swift index 322df399..02d60da5 100644 --- a/framework/Source/RawDataInput.swift +++ b/framework/Source/RawDataInput.swift @@ -37,12 +37,7 @@ public class RawDataInput: ImageSource { } public func uploadBytes(bytes:[UInt8], size:Size, pixelFormat:PixelFormat, orientation:ImageOrientation = .Portrait) { - let dataFramebuffer:Framebuffer - do { - dataFramebuffer = try Framebuffer(context:sharedImageProcessingContext, orientation:orientation, size:GLSize(size), textureOnly:true, internalFormat:pixelFormat.toGL(), format:pixelFormat.toGL()) - } catch { - fatalError("ERROR: Unable to initialize framebuffer of size (\(size)) with error: \(error)") - } + let dataFramebuffer = sharedImageProcessingContext.framebufferCache.requestFramebufferWithProperties(orientation:orientation, size:GLSize(size), textureOnly:true, internalFormat:pixelFormat.toGL(), format:pixelFormat.toGL()) glActiveTexture(GLenum(GL_TEXTURE1)) glBindTexture(GLenum(GL_TEXTURE_2D), dataFramebuffer.texture) diff --git a/framework/Source/RawDataOutput.swift b/framework/Source/RawDataOutput.swift index 4cfdded5..6985bc7c 100644 --- a/framework/Source/RawDataOutput.swift +++ b/framework/Source/RawDataOutput.swift @@ -29,7 +29,8 @@ public class RawDataOutput: ImageConsumer { renderFramebuffer.activateFramebufferForRendering() clearFramebufferWithColor(Color.Black) renderQuadWithShader(sharedImageProcessingContext.passthroughShader, uniformSettings:ShaderUniformSettings(), vertices:standardImageVertices, inputTextures:[framebuffer.texturePropertiesForOutputRotation(.NoRotation)]) - + framebuffer.unlock() + var data = [UInt8](count:Int(framebuffer.size.width * framebuffer.size.height * 4), repeatedValue:0) glReadPixels(0, 0, framebuffer.size.width, framebuffer.size.height, GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), &data) renderFramebuffer.unlock()