Last active
December 6, 2018 03:03
-
-
Save btomtom5/bf9609d2cac176dca5e9074af5f2fdae to your computer and use it in GitHub Desktop.
PixelBuffer Operations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| func drawSolidCircle(imageBuffer: CVPixelBuffer, pnt: (Int, Int), radius: Int) { | |
| /* | |
| Marks CVPixelBuffer with a solid green circle of radius r | |
| imageBuffer: CVPixelBuffer needs to be already locked and available for write access. | |
| */ | |
| CVPixelBufferLockBaseAddress(imageBuffer, .init(rawValue: 0)) | |
| let width: Int = CVPixelBufferGetWidth(imageBuffer) | |
| let height: Int = CVPixelBufferGetHeight(imageBuffer) | |
| var positionsEarmarked: [Int] = [] | |
| for i in -radius...radius { | |
| for j in -radius...radius { | |
| let x = pnt.0 + i | |
| let y = pnt.1 + j | |
| if (x >= 0 && x < width) && (y >= 0 && y < height) { | |
| positionsEarmarked.append(x + y * width) | |
| } | |
| } | |
| } | |
| let baseAddress: UnsafeMutablePointer<UInt8> = CVPixelBufferGetBaseAddress(imageBuffer)!.assumingMemoryBound(to: UInt8.self) | |
| for position in positionsEarmarked { | |
| let offset = position * 4 | |
| baseAddress[offset] = 0 | |
| baseAddress[offset + 1] = 255 | |
| baseAddress[offset + 2] = 0 | |
| // Alpha channel [offset + 3] is left unmodified | |
| } | |
| CVPixelBufferUnlockBaseAddress(imageBuffer, .init(rawValue: 0)) | |
| } | |
| func drawBoundingBox(imageBuffer: CVPixelBuffer, boundingBox: CGRect) { | |
| for xCoord in 0..<Int(boundingBox.width) { | |
| drawSolidCircle(imageBuffer: imageBuffer, pnt: (Int(boundingBox.minX) + xCoord, Int(boundingBox.minY)), radius: 1) | |
| drawSolidCircle(imageBuffer: imageBuffer, pnt: (Int(boundingBox.minX) + xCoord, Int(boundingBox.maxY)), radius: 1) | |
| } | |
| for yCoord in 0..<Int(boundingBox.height) { | |
| drawSolidCircle(imageBuffer: imageBuffer, pnt: (Int(boundingBox.minX), Int(boundingBox.minY) + yCoord), radius: 1) | |
| drawSolidCircle(imageBuffer: imageBuffer, pnt: (Int(boundingBox.maxX), Int(boundingBox.minY) + yCoord), radius: 1) | |
| } | |
| } | |
| func buffer(from image: UIImage) -> CVPixelBuffer? { | |
| let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary | |
| var pixelBuffer : CVPixelBuffer? | |
| let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(image.size.width), Int(image.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer) | |
| guard (status == kCVReturnSuccess) else { | |
| return nil | |
| } | |
| CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) | |
| let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!) | |
| let rgbColorSpace = CGColorSpaceCreateDeviceRGB() | |
| let context = CGContext(data: pixelData, width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) | |
| context?.translateBy(x: 0, y: image.size.height) | |
| context?.scaleBy(x: 1.0, y: -1.0) | |
| UIGraphicsPushContext(context!) | |
| image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)) | |
| UIGraphicsPopContext() | |
| CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) | |
| return pixelBuffer | |
| } | |
| func fillPixelBuffer(imageBuffer: CVPixelBuffer, newValue: UInt8) -> Void{ | |
| CVPixelBufferLockBaseAddress(imageBuffer, []) | |
| let width: Int = CVPixelBufferGetWidth(imageBuffer) | |
| let height: Int = CVPixelBufferGetHeight(imageBuffer) | |
| let baseAddress: UnsafeMutablePointer<UInt8> = CVPixelBufferGetBaseAddress(imageBuffer)!.assumingMemoryBound(to: UInt8.self) | |
| for rowIndex in 0..<width { | |
| for colIndex in 0..<height{ | |
| let offset = rowIndex * width * 4 + colIndex * 4 | |
| baseAddress[offset] = newValue | |
| baseAddress[offset + 1] = newValue | |
| baseAddress[offset + 2] = newValue | |
| // Alpha channel [offset + 3] is left unmodified | |
| } | |
| } | |
| CVPixelBufferUnlockBaseAddress(imageBuffer, []) | |
| } | |
| func drawFacialLandmarks(imageBuffer: CVPixelBuffer, facialLandmarksX: [Double], facialLandmarksY: [Double]) -> Void{ | |
| guard facialLandmarksX.count == facialLandmarksY.count && facialLandmarksY.count == 68 else { | |
| fatalError("improper shape for facialLandmarks. landmarksX:\(facialLandmarksX.count) | landmarksY:\(facialLandmarksY.count)") | |
| } | |
| CVPixelBufferLockBaseAddress(imageBuffer, []) | |
| for index in 0..<facialLandmarksX.count { | |
| let newPoint = (Int(facialLandmarksX[index]), Int(facialLandmarksY[index])) | |
| drawSolidCircle(imageBuffer: imageBuffer, pnt: newPoint, radius: 2) | |
| } | |
| CVPixelBufferUnlockBaseAddress(imageBuffer, []) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment