Skip to content

Instantly share code, notes, and snippets.

@kemchenj
Last active January 10, 2023 06:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kemchenj/c5a8f900a50ec2be99ef5db56a3c6653 to your computer and use it in GitHub Desktop.
Save kemchenj/c5a8f900a50ec2be99ef5db56a3c6653 to your computer and use it in GitHub Desktop.
/*
See LICENSE folder for this sample’s licensing information.
Abstract:
Blur Detector Object.
*/
import AVFoundation
import Accelerate
import UIKit
import SwiftUI
import Combine
// MARK: BlurDetector
class BlurDetector: NSObject {
let laplacian: [Float] = [-1, -1, -1,
-1, 8, -1,
-1, -1, -1]
func processImage(data: UnsafeMutableRawPointer,
rowBytes: Int,
width: Int, height: Int,
sequenceCount: Int,
expectedCount: Int,
orientation: UInt32? ) {
var sourceBuffer = vImage_Buffer(data: data,
height: vImagePixelCount(height),
width: vImagePixelCount(width),
rowBytes: rowBytes)
var floatPixels: [Float]
let count = width * height
if sourceBuffer.rowBytes == width * MemoryLayout<Pixel_8>.stride {
let start = sourceBuffer.data.assumingMemoryBound(to: Pixel_8.self)
floatPixels = vDSP.integerToFloatingPoint(
UnsafeMutableBufferPointer(start: start,
count: count),
floatingPointType: Float.self)
} else {
floatPixels = [Float](unsafeUninitializedCapacity: count) {
buffer, initializedCount in
var floatBuffer = vImage_Buffer(data: buffer.baseAddress,
height: sourceBuffer.height,
width: sourceBuffer.width,
rowBytes: width * MemoryLayout<Float>.size)
vImageConvert_Planar8toPlanarF(&sourceBuffer,
&floatBuffer,
0, 255,
vImage_Flags(kvImageNoFlags))
initializedCount = count
}
}
// Convolve with Laplacian.
vDSP.convolve(floatPixels,
rowCount: height,
columnCount: width,
with3x3Kernel: laplacian,
result: &floatPixels)
// Calculate standard deviation.
var mean = Float.nan
var stdDev = Float.nan
vDSP_normalize(floatPixels, 1,
nil, 1,
&mean, &stdDev,
vDSP_Length(count))
// Create display version of laplacian convolution.
let clippedPixels = vDSP.clip(floatPixels, to: 0 ... 255)
var pixel8Pixels = vDSP.floatingPointToInteger(clippedPixels,
integerType: UInt8.self,
rounding: .towardNearestInteger)
// Create display images.
if
let orientation = orientation,
let imagePropertyOrientation = CGImagePropertyOrientation(rawValue: orientation),
let laplacianImage = BlurDetector.makeImage(fromPixels: &pixel8Pixels,
width: width, height: height,
gamma: 1 / 2.2,
orientation: imagePropertyOrientation),
let monoImage = BlurDetector.makeImage(fromPlanarBuffer: sourceBuffer,
orientation: imagePropertyOrientation) {
let result = BlurDetectionResult(index: sequenceCount,
image: monoImage,
laplacianImage: laplacianImage,
score: stdDev * stdDev)
print("index \(sequenceCount) : score \(stdDev * stdDev)")
DispatchQueue.main.async {
self.processedCount += 1
self.resultsDelegate?.itemProcessed(result)
if self.processedCount == expectedCount {
self.resultsDelegate?.finishedProcessing()
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment