Skip to content

Commit

Permalink
Merge pull request #2 from syjdev/task/add_AVCaptureSession
Browse files Browse the repository at this point in the history
add CaptureSession & make a demo view
  • Loading branch information
syjdev authored Jan 24, 2021
2 parents 3bc3cf2 + 9dd9556 commit 6a975d5
Show file tree
Hide file tree
Showing 13 changed files with 424 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,30 @@

/* Begin PBXBuildFile section */
DE0E8AE825BC091400D65C7A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0E8AE725BC091400D65C7A /* AppDelegate.swift */; };
DE0E8AEA25BC091400D65C7A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0E8AE925BC091400D65C7A /* SceneDelegate.swift */; };
DE0E8AEC25BC091400D65C7A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0E8AEB25BC091400D65C7A /* ViewController.swift */; };
DE0E8AEF25BC091400D65C7A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE0E8AED25BC091400D65C7A /* Main.storyboard */; };
DE0E8AF125BC091700D65C7A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE0E8AF025BC091700D65C7A /* Assets.xcassets */; };
DE0E8AF425BC091700D65C7A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE0E8AF225BC091700D65C7A /* LaunchScreen.storyboard */; };
DE0E8AFD25BC0BBC00D65C7A /* BlurDiscriminator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0E8AFC25BC0BBC00D65C7A /* BlurDiscriminator.swift */; };
DE0E8B0225BC6A3B00D65C7A /* MTLComputeCommandEncoder+encodeThreadgroupSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0E8B0125BC6A3B00D65C7A /* MTLComputeCommandEncoder+encodeThreadgroupSize.swift */; };
DE0E8B0625BC6AB900D65C7A /* ShaderFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0E8B0525BC6AB900D65C7A /* ShaderFunctions.swift */; };
DE0E8B0C25BC6F0500D65C7A /* BlurDiscriminatorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0E8B0B25BC6F0500D65C7A /* BlurDiscriminatorError.swift */; };
DEC70F0625BD5816003D8944 /* CaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC70F0525BD5816003D8944 /* CaptureSession.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
DE0E8AE425BC091400D65C7A /* BlurDiscriminator-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "BlurDiscriminator-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
DE0E8AE725BC091400D65C7A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
DE0E8AE925BC091400D65C7A /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
DE0E8AEB25BC091400D65C7A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
DE0E8AEE25BC091400D65C7A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
DE0E8AF025BC091700D65C7A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
DE0E8AF325BC091700D65C7A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
DE0E8AF525BC091700D65C7A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DE0E8AFC25BC0BBC00D65C7A /* BlurDiscriminator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurDiscriminator.swift; sourceTree = "<group>"; };
DE0E8B0125BC6A3B00D65C7A /* MTLComputeCommandEncoder+encodeThreadgroupSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MTLComputeCommandEncoder+encodeThreadgroupSize.swift"; sourceTree = "<group>"; };
DE0E8B0525BC6AB900D65C7A /* ShaderFunctions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShaderFunctions.swift; sourceTree = "<group>"; };
DE0E8B0B25BC6F0500D65C7A /* BlurDiscriminatorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurDiscriminatorError.swift; sourceTree = "<group>"; };
DEC70F0525BD5816003D8944 /* CaptureSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptureSession.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -56,17 +64,37 @@
DE0E8AE625BC091400D65C7A /* BlurDiscriminator-iOS */ = {
isa = PBXGroup;
children = (
DEC70F0425BD5433003D8944 /* CaptureView */,
DE0E8B0025BC6A0700D65C7A /* BlurDiscriminator */,
DE0E8AE725BC091400D65C7A /* AppDelegate.swift */,
DE0E8AE925BC091400D65C7A /* SceneDelegate.swift */,
DE0E8AEB25BC091400D65C7A /* ViewController.swift */,
DE0E8AED25BC091400D65C7A /* Main.storyboard */,
DE0E8AF025BC091700D65C7A /* Assets.xcassets */,
DE0E8AF225BC091700D65C7A /* LaunchScreen.storyboard */,
DE0E8AF025BC091700D65C7A /* Assets.xcassets */,
DE0E8AF525BC091700D65C7A /* Info.plist */,
);
path = "BlurDiscriminator-iOS";
sourceTree = "<group>";
};
DE0E8B0025BC6A0700D65C7A /* BlurDiscriminator */ = {
isa = PBXGroup;
children = (
DE0E8AFC25BC0BBC00D65C7A /* BlurDiscriminator.swift */,
DE0E8B0B25BC6F0500D65C7A /* BlurDiscriminatorError.swift */,
DE0E8B0125BC6A3B00D65C7A /* MTLComputeCommandEncoder+encodeThreadgroupSize.swift */,
DE0E8B0525BC6AB900D65C7A /* ShaderFunctions.swift */,
);
path = BlurDiscriminator;
sourceTree = "<group>";
};
DEC70F0425BD5433003D8944 /* CaptureView */ = {
isa = PBXGroup;
children = (
DE0E8AED25BC091400D65C7A /* Main.storyboard */,
DE0E8AEB25BC091400D65C7A /* ViewController.swift */,
DEC70F0525BD5816003D8944 /* CaptureSession.swift */,
);
path = CaptureView;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -137,9 +165,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DE0E8B0625BC6AB900D65C7A /* ShaderFunctions.swift in Sources */,
DE0E8AEC25BC091400D65C7A /* ViewController.swift in Sources */,
DE0E8AE825BC091400D65C7A /* AppDelegate.swift in Sources */,
DE0E8AEA25BC091400D65C7A /* SceneDelegate.swift in Sources */,
DE0E8B0225BC6A3B00D65C7A /* MTLComputeCommandEncoder+encodeThreadgroupSize.swift in Sources */,
DE0E8B0C25BC6F0500D65C7A /* BlurDiscriminatorError.swift in Sources */,
DEC70F0625BD5816003D8944 /* CaptureSession.swift in Sources */,
DE0E8AFD25BC0BBC00D65C7A /* BlurDiscriminator.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -289,6 +321,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = NHMWTHTL9L;
INFOPLIST_FILE = "BlurDiscriminator-iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -308,6 +341,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = NHMWTHTL9L;
INFOPLIST_FILE = "BlurDiscriminator-iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
18 changes: 1 addition & 17 deletions BlurDiscriminator-iOS/BlurDiscriminator-iOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,12 @@ import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {


var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}


}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// BlurDiscriminator.swift
// BlurDiscriminator-iOS
//
// Created by syjdev on 2021/01/23.
//

import Metal
import MetalPerformanceShaders
import MetalKit


class BlurDiscriminator {

let mtlDevice: MTLDevice
let library: MTLLibrary
var commandQueue: MTLCommandQueue?
let computePipelineState: MTLComputePipelineState

init() throws {
guard let mtlDevice = MTLCreateSystemDefaultDevice() else {
throw BlurDiscriminatorError.mtlDeviceWasCorrupted
}

guard MPSSupportsMTLDevice(mtlDevice) else {
throw BlurDiscriminatorError.unsupportedDevice
}

self.mtlDevice = mtlDevice
self.commandQueue = self.mtlDevice.makeCommandQueue()

do {
self.library = try self.mtlDevice.makeLibrary(source: shaderFunction, options: nil)
} catch {
throw error
}

guard let kernelFunction = self.library.makeFunction(name: "changeToGrayscale") else {
throw BlurDiscriminatorError.unsupportedDevice
}

self.computePipelineState = try self.mtlDevice.makeComputePipelineState(function: kernelFunction)
}

func calculateGrayscaledPixelVariance(cgImage: CGImage) -> Result<Float, Error> {
if self.commandQueue == nil {
self.commandQueue = self.mtlDevice.makeCommandQueue()
}

guard let commandQueue = self.commandQueue,
let commandBuffer = commandQueue.makeCommandBuffer(),
let commandEncoder = commandBuffer.makeComputeCommandEncoder()
else {
return .failure(BlurDiscriminatorError.commandWasCorrupted)
}

let textureLoader = MTKTextureLoader(device: self.mtlDevice)
let texture: MTLTexture
do {
texture = try textureLoader.newTexture(cgImage: cgImage, options: nil)
} catch {
return .failure(BlurDiscriminatorError.failedToMakeTexture)
}

let imageDescriptor = MPSImageDescriptor(channelFormat: .float32, width: cgImage.width, height: cgImage.height, featureChannels: 1)
let inputImage = MPSImage(texture: texture, featureChannels: 3)
let grayscaledImage = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: imageDescriptor)

commandEncoder.setComputePipelineState(self.computePipelineState)
commandEncoder.setTexture(inputImage.texture, index: 0)
commandEncoder.setTexture(grayscaledImage.texture, index: 1)

commandEncoder.dispatchThreadgroups(texture: texture, computePipelineState: self.computePipelineState)
commandEncoder.endEncoding()

let laplacian = MPSImageLaplacian(device: self.mtlDevice)
let laplacianImage = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: imageDescriptor)
laplacian.encode(commandBuffer: commandBuffer, sourceImage: grayscaledImage, destinationImage: laplacianImage)

let imageStatisticsMeanAndVariance = MPSImageStatisticsMeanAndVariance(device: self.mtlDevice)
let varianceDescriptor = MPSImageDescriptor(channelFormat: .float32, width: 2, height: 1, featureChannels: 1)
let statisticsImage = MPSImage(device: self.mtlDevice, imageDescriptor: varianceDescriptor)
imageStatisticsMeanAndVariance.encode(commandBuffer: commandBuffer, sourceImage: laplacianImage, destinationImage: statisticsImage)

commandBuffer.commit()
commandBuffer.waitUntilCompleted()

var variance: Float = 0
statisticsImage.texture.getBytes(
&variance,
bytesPerRow: statisticsImage.texture.width * MemoryLayout<Float>.size,
from: MTLRegionMake2D(1, 0, 1, 1),
mipmapLevel: 0
)

return .success(variance)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// BlurDiscriminatorError.swift
// BlurDiscriminator-iOS
//
// Created by syjdev on 2021/01/23.
//

import Foundation

enum BlurDiscriminatorError: Error {
case mtlDeviceWasCorrupted
case unsupportedDevice
case shaderFunctionWasCorrupted
case commandWasCorrupted
case failedToMakeTexture
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// MTLComputeCommandEncoder+encodeThreadgroupSize.swift
// BlurDiscriminator-iOS
//
// Created by syjdev on 2021/01/23.
//

import Metal


extension MTLComputeCommandEncoder {
/// calculate a suitable threadgroups, then call dispatchThreadgroups.
///
/// You can see a apple's guide, "https://developer.apple.com/documentation/metal/calculating_threadgroup_and_grid_sizes"
///
func dispatchThreadgroups(texture: MTLTexture, computePipelineState: MTLComputePipelineState) {
let width = computePipelineState.threadExecutionWidth
let height = computePipelineState.maxTotalThreadsPerThreadgroup / width
let threadsPerThreadgroup = MTLSizeMake(width, height, 1)

let threadgroupsPerGrid = MTLSize(width: (texture.width + width - 1) / width,
height: (texture.height + height - 1) / height,
depth: 1)

self.dispatchThreadgroups(threadgroupsPerGrid, threadsPerThreadgroup: threadsPerThreadgroup)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// ShaderFunctions.swift
// BlurDiscriminator-iOS
//
// Created by syjdev on 2021/01/23.
//

import Foundation


internal let shaderFunction = """
using namespace metal;
constant float3 rgbDegree = float3(0.3333, 0.3333, 0.3333);
kernel void changeToGrayscale(texture2d<float, access::read> input [[ texture(0) ]],
texture2d<float, access::write> output [[ texture(1) ]],
uint2 gid [[ thread_position_in_grid ]])
{
if((gid.x < output.get_width()) && (gid.y < output.get_height()))
{
float4 pixel = input.read(gid);
float grayscaledRgb = dot(pixel.rgb, rgbDegree);
float4 grayscaledPixel = float4(grayscaledRgb, grayscaledRgb, grayscaledRgb, 1.0) * 255.0;
output.write(grayscaledPixel, gid);
}
}
"""
Loading

0 comments on commit 6a975d5

Please sign in to comment.