Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hough lines - osx only #94

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions examples/Mac/FilterShowcase/FilterShowcase/FilterOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,63 @@ let filterOperations: Array<FilterOperationInterface> = [
},
filterOperationType:.singleInput
),
FilterOperation(
filter:{ParallelCoordinateLineTransform()},
listName:"Parallel Coordinate Tester",
titleName:"Parallel Coordinate Tester",
sliderConfiguration:.enabled(minimumValue:0.01, maximumValue:0.70, initialValue:0.20),
sliderUpdateCallback: {(filter, sliderValue) in
// filter.threshold = sliderValue
},
filterOperationType:.custom(filterSetupFunction:{(camera, filter, outputView) in
let castFilter = filter as! ParallelCoordinateLineTransform
// TODO: Get this more dynamically sized
let thresholdEdgeDetectionFilter = CannyEdgeDetection()
let parallelCoordsTransformFilter = ParallelCoordinateLineTransform()
let nonMaximumSuppression = TextureSamplingOperation(fragmentShader:ThresholdedNonMaximumSuppressionFragmentShader)
var threshold:Float = 0.2 { didSet { nonMaximumSuppression.uniformSettings["threshold"] = threshold } }
nonMaximumSuppression.uniformSettings["threshold"] = 0.2
// let directionalNonMaximumSuppression = TextureSamplingOperation(vertexShader:OneInputVertexShader, fragmentShader:DirectionalNonMaximumSuppressionFragmentShader)

// camera --> thresholdEdgeDetectionFilter --> castFilter --> outputView
camera --> thresholdEdgeDetectionFilter --> castFilter --> outputView

// camera --> thresholdEdgeDetectionFilter --> castFilter --> nonMaximumSuppression --> outputView
return nil
})

),
FilterOperation(
filter:{HoughTransformLineDetector()},
listName:"Hough Line detector",
titleName:"Hough Line Detector",
sliderConfiguration:.enabled(minimumValue:0.01, maximumValue:0.70, initialValue:0.20),
sliderUpdateCallback: {(filter, sliderValue) in
filter.lineDetectionThreshold = sliderValue
},
filterOperationType:.custom(filterSetupFunction:{(camera, filter, outputView) in
let castFilter = filter as! HoughTransformLineDetector
// TODO: Get this more dynamically sized
#if os(iOS)
let lineGenerator = LineGenerator(size:Size(width:480, height:640))
#else
let lineGenerator = LineGenerator(size:Size(width:1280, height:720))
#endif

castFilter.linesDetectedCallback = { lines in
lineGenerator.renderLines(lines)
}

camera --> castFilter

let blendFilter = AlphaBlend()
camera --> blendFilter --> outputView
lineGenerator --> blendFilter

return blendFilter
})
),

FilterOperation(
filter:{HarrisCornerDetector()},
listName:"Harris corner detector",
Expand Down
18 changes: 18 additions & 0 deletions framework/GPUImage-Mac.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
objects = {

/* Begin PBXBuildFile section */
503409CF1D52FECA00BC789C /* ParallelCoordinateLineTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503409CE1D52FECA00BC789C /* ParallelCoordinateLineTransform.swift */; };
503409D31D56B10100BC789C /* HoughTransformLineDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503409D21D56B10100BC789C /* HoughTransformLineDetector.swift */; };
503409D91D58431900BC789C /* ParallelCoordinateLineTransformFBORead_GL.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 503409D81D58431900BC789C /* ParallelCoordinateLineTransformFBORead_GL.fsh */; };
503409DB1D58577A00BC789C /* ParallelCoordinateLineTransform.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 503409DA1D58577A00BC789C /* ParallelCoordinateLineTransform.vsh */; };
BC09239E1C92658200A2ADFA /* ShaderProgram_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC09239D1C92658200A2ADFA /* ShaderProgram_Tests.swift */; };
BC0923A11C92661D00A2ADFA /* Pipeline_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC09239F1C9265A600A2ADFA /* Pipeline_Tests.swift */; };
BC0923A21C92664900A2ADFA /* Framebuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB279EB1C8D11630013E213 /* Framebuffer.swift */; };
Expand Down Expand Up @@ -193,6 +197,11 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
503409CE1D52FECA00BC789C /* ParallelCoordinateLineTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ParallelCoordinateLineTransform.swift; path = Source/Operations/ParallelCoordinateLineTransform.swift; sourceTree = "<group>"; };
503409D01D52FF1D00BC789C /* ParallelCoordinateLineTransform_GL.fsh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.glsl; name = ParallelCoordinateLineTransform_GL.fsh; path = Source/Operations/Shaders/ParallelCoordinateLineTransform_GL.fsh; sourceTree = "<group>"; };
503409D21D56B10100BC789C /* HoughTransformLineDetector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HoughTransformLineDetector.swift; path = Source/Operations/HoughTransformLineDetector.swift; sourceTree = "<group>"; };
503409D81D58431900BC789C /* ParallelCoordinateLineTransformFBORead_GL.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = ParallelCoordinateLineTransformFBORead_GL.fsh; path = Source/Operations/Shaders/ParallelCoordinateLineTransformFBORead_GL.fsh; sourceTree = "<group>"; };
503409DA1D58577A00BC789C /* ParallelCoordinateLineTransform.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = ParallelCoordinateLineTransform.vsh; path = Source/Operations/Shaders/ParallelCoordinateLineTransform.vsh; sourceTree = "<group>"; };
BC09239D1C92658200A2ADFA /* ShaderProgram_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShaderProgram_Tests.swift; path = Tests/ShaderProgram_Tests.swift; sourceTree = SOURCE_ROOT; };
BC09239F1C9265A600A2ADFA /* Pipeline_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Pipeline_Tests.swift; path = Tests/Pipeline_Tests.swift; sourceTree = SOURCE_ROOT; };
BC1E12F41C9F2FD7008F844F /* ThreeInput.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = ThreeInput.vsh; path = Source/Operations/Shaders/ThreeInput.vsh; sourceTree = "<group>"; };
Expand Down Expand Up @@ -720,6 +729,11 @@
BCA4E2481CC3EF26007B51BA /* ColourFASTFeatureDetection.swift */,
BCA4E24B1CC3F3C5007B51BA /* ColourFASTDecriptor.vsh */,
BCA4E24A1CC3F3C5007B51BA /* ColourFASTDecriptor_GL.fsh */,
503409CE1D52FECA00BC789C /* ParallelCoordinateLineTransform.swift */,
503409DA1D58577A00BC789C /* ParallelCoordinateLineTransform.vsh */,
503409D81D58431900BC789C /* ParallelCoordinateLineTransformFBORead_GL.fsh */,
503409D01D52FF1D00BC789C /* ParallelCoordinateLineTransform_GL.fsh */,
503409D21D56B10100BC789C /* HoughTransformLineDetector.swift */,
);
name = "Image processing";
sourceTree = "<group>";
Expand Down Expand Up @@ -1012,6 +1026,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
503409D91D58431900BC789C /* ParallelCoordinateLineTransformFBORead_GL.fsh in Resources */,
503409DB1D58577A00BC789C /* ParallelCoordinateLineTransform.vsh in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1100,6 +1116,7 @@
BC7FD11A1CB0793900037949 /* MultiplyBlend.swift in Sources */,
BCA4E2591CC3F832007B51BA /* ColorLocalBinaryPattern.swift in Sources */,
BCBEC0FA1CCD993900B70ED7 /* MovieInput.swift in Sources */,
503409D31D56B10100BC789C /* HoughTransformLineDetector.swift in Sources */,
BC4EE1561CB3457800AD8A65 /* PrewittEdgeDetection.swift in Sources */,
BCB825B61CC9C1F100339790 /* MovieOutput.swift in Sources */,
BCFF46D31CB9C24500A0C521 /* HarrisCornerDetector.swift in Sources */,
Expand Down Expand Up @@ -1142,6 +1159,7 @@
BC7FD1241CB07A0100037949 /* SoftLightBlend.swift in Sources */,
BC4EE1521CB3445500AD8A65 /* SobelEdgeDetection.swift in Sources */,
BC7FD1221CB079DD00037949 /* ScreenBlend.swift in Sources */,
503409CF1D52FECA00BC789C /* ParallelCoordinateLineTransform.swift in Sources */,
BCB279EC1C8D11630013E213 /* Framebuffer.swift in Sources */,
BCA4E2301CC31276007B51BA /* Solarize.swift in Sources */,
BC7FD19F1CB20B1300037949 /* LineGenerator.swift in Sources */,
Expand Down
101 changes: 101 additions & 0 deletions framework/Source/Operations/HoughTransformLineDetector.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#if os(Linux)
#if GLES
import COpenGLES.gles2
#else
import COpenGL
#endif
#else
#if GLES
import OpenGLES
#else
import OpenGL.GL3
#endif
#endif

//
// HoughTransformLineDetector.swift
// GPUImage-Mac
//
// Created by Max Cantor on 8/6/16.
// Copyright © 2016 Sunset Lake Software LLC. All rights reserved.
//

import Foundation

public class HoughTransformLineDetector: OperationGroup {

let thresholdEdgeDetectionFilter = CannyEdgeDetection()
let nonMaximumSuppression = TextureSamplingOperation(fragmentShader:ThresholdedNonMaximumSuppressionFragmentShader)

public var linesDetectedCallback:(([Line]) -> ())?
public var edgeThreshold:Float = 0.9
public var lineDetectionThreshold:Float = 0.2 { didSet { nonMaximumSuppression.uniformSettings["threshold"] = lineDetectionThreshold } }
public var cannyBlurRadiusInPixels:Float = 2.0 { didSet { thresholdEdgeDetectionFilter.blurRadiusInPixels = cannyBlurRadiusInPixels } }
public var cannyUpperThreshold:Float = 0.4 { didSet { thresholdEdgeDetectionFilter.upperThreshold = cannyUpperThreshold } }
public var cannyLowerThreshold:Float = 0.1 { didSet { thresholdEdgeDetectionFilter.lowerThreshold = cannyLowerThreshold } }

public override init() {
super.init()
let parallelCoordsTransformFilter = ParallelCoordinateLineTransform()
nonMaximumSuppression.uniformSettings["threshold"] = lineDetectionThreshold

outputImageRelay.newImageCallback = {[weak self] framebuffer in
if let linesDetectedCallback = self?.linesDetectedCallback {
linesDetectedCallback(extractLinesFromImage(framebuffer: framebuffer))
}
}

self.configureGroup {input, output in
input --> self.thresholdEdgeDetectionFilter --> parallelCoordsTransformFilter --> self.nonMaximumSuppression --> output
}
}
}

func extractLinesFromImage(framebuffer: Framebuffer) -> [Line] {
let frameSize = framebuffer.size
let pixCount = UInt32(frameSize.width * frameSize.height)
let chanCount: UInt32 = 4
let imageByteSize = Int(pixCount * chanCount) // since we're comparing to currentByte, might as well cast here
let rawImagePixels = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(imageByteSize))
glReadPixels(0, 0, frameSize.width, frameSize.height, GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), rawImagePixels)
// since we only set one position with each iteration of the loop, we'll have ot set positions then combine into lines
// linesArray = calloc(1024 * 2, sizeof(GLfloat)); - lines is 2048 floats - which is 1024 positions or 528 lines
var lines = Array<Line>()

let imageWidthInt = Int(framebuffer.size.width * 4)
// let startTime = CFAbsoluteTimeGetCurrent()
var currentByte:Int = 0
// var cornerStorageIndex: UInt32 = 0
var lineStrengthCounter: UInt64 = 0
while (currentByte < imageByteSize) {
let colorByte = rawImagePixels[currentByte]
if (colorByte > 0) {
let xCoordinate = currentByte % imageWidthInt
let yCoordinate = currentByte / imageWidthInt
lineStrengthCounter += UInt64(colorByte)
let normalizedXCoordinate = -1.0 + 2.0 * (Float)(xCoordinate / 4) / Float(frameSize.width)
let normalizedYCoordinate = -1.0 + 2.0 * (Float)(yCoordinate) / Float(frameSize.height)
// print("(\(xCoordinate), \(yCoordinate)), [\(rawImagePixels[currentByte]), \(rawImagePixels[currentByte+1]), \(rawImagePixels[currentByte+2]), \(rawImagePixels[currentByte+3]) ] ")
let nextLine =
( normalizedXCoordinate < 0.0
? ( normalizedXCoordinate > -0.05
// T space
// m = -1 - d/u
// b = d * v/u
? Line.infinite(slope:100000.0, intercept: normalizedYCoordinate)
: Line.infinite(slope: -1.0 - 1.0 / normalizedXCoordinate, intercept: 1.0 * normalizedYCoordinate / normalizedXCoordinate)
)
: ( normalizedXCoordinate < 0.05
// S space
// m = 1 - d/u
// b = d * v/u
? Line.infinite(slope: 100000.0, intercept: normalizedYCoordinate)
: Line.infinite(slope: 1.0 - 1.0 / normalizedXCoordinate,intercept: 1.0 * normalizedYCoordinate / normalizedXCoordinate)
)
)
lines.append(nextLine)
}
currentByte += 4
}
return lines
}
Loading