vision-camera-face-detection 2.1.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/VisionCameraFaceDetection.podspec +1 -1
- package/android/build.gradle +0 -1
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/visioncamerafacedetection/VisionCameraFaceDetectionPlugin.kt +100 -83
- package/android/src/main/java/com/visioncamerafacedetection/VisionCameraFaceDetectorOrientation.kt +57 -0
- package/ios/FaceHelper.swift +103 -220
- package/ios/VisionCameraFaceDetectionPlugin.swift +326 -306
- package/ios/VisionCameraFaceDetectorOrientation.swift +81 -0
- package/lib/commonjs/Camera.js +58 -34
- package/lib/commonjs/Camera.js.map +1 -1
- package/lib/commonjs/FaceDetector.js.map +1 -1
- package/lib/module/Camera.js +60 -34
- package/lib/module/Camera.js.map +1 -1
- package/lib/module/FaceDetector.js.map +1 -1
- package/lib/typescript/commonjs/src/Camera.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/FaceDetector.d.ts +24 -6
- package/lib/typescript/commonjs/src/FaceDetector.d.ts.map +1 -1
- package/lib/typescript/module/src/Camera.d.ts.map +1 -1
- package/lib/typescript/module/src/FaceDetector.d.ts +24 -6
- package/lib/typescript/module/src/FaceDetector.d.ts.map +1 -1
- package/package.json +6 -7
- package/src/Camera.tsx +65 -33
- package/src/FaceDetector.ts +31 -6
package/ios/FaceHelper.swift
CHANGED
|
@@ -16,243 +16,126 @@ let inputHeight = 112
|
|
|
16
16
|
var interpreter: Interpreter? = nil
|
|
17
17
|
|
|
18
18
|
class FaceHelper {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// "LEFT_EYEBROW_TOP",
|
|
41
|
-
// "LEFT_EYEBROW_BOTTOM",
|
|
42
|
-
// "RIGHT_EYEBROW_TOP",
|
|
43
|
-
// "RIGHT_EYEBROW_BOTTOM",
|
|
44
|
-
// "LEFT_EYE",
|
|
45
|
-
// "RIGHT_EYE",
|
|
46
|
-
// "UPPER_LIP_TOP",
|
|
47
|
-
// "UPPER_LIP_BOTTOM",
|
|
48
|
-
// "LOWER_LIP_TOP",
|
|
49
|
-
// "LOWER_LIP_BOTTOM",
|
|
50
|
-
// "NOSE_BRIDGE",
|
|
51
|
-
// "NOSE_BOTTOM",
|
|
52
|
-
// "LEFT_CHEEK",
|
|
53
|
-
// "RIGHT_CHEEK",
|
|
54
|
-
// ];
|
|
55
|
-
|
|
56
|
-
// var faceContoursTypesMap: [String:[[String:CGFloat]]] = [:]
|
|
57
|
-
|
|
58
|
-
// for i in 0..<faceContoursTypes.count {
|
|
59
|
-
// let contour = face.contour(ofType: faceContoursTypes[i]);
|
|
60
|
-
|
|
61
|
-
// var pointsArray: [[String:CGFloat]] = []
|
|
62
|
-
|
|
63
|
-
// if let points = contour?.points {
|
|
64
|
-
// for point in points {
|
|
65
|
-
// let currentPointsMap = [
|
|
66
|
-
// "x": point.x,
|
|
67
|
-
// "y": point.y,
|
|
68
|
-
// ]
|
|
69
|
-
|
|
70
|
-
// pointsArray.append(currentPointsMap)
|
|
71
|
-
// }
|
|
72
|
-
|
|
73
|
-
// faceContoursTypesMap[faceContoursTypesStrings[i]] = pointsArray
|
|
74
|
-
// }
|
|
75
|
-
// }
|
|
76
|
-
|
|
77
|
-
// return faceContoursTypesMap
|
|
78
|
-
// }
|
|
79
|
-
|
|
80
|
-
// static func processBoundingBox(from face: Face) -> [String:Any] {
|
|
81
|
-
// let frameRect = face.frame
|
|
82
|
-
|
|
83
|
-
// let offsetX = (frameRect.midX - ceil(frameRect.width)) / 2.0
|
|
84
|
-
// let offsetY = (frameRect.midY - ceil(frameRect.height)) / 2.0
|
|
19
|
+
|
|
20
|
+
static func getImageFaceFromUIImage(from image: UIImage, rectImage: CGRect) -> UIImage? {
|
|
21
|
+
let imageRef: CGImage = (image.cgImage?.cropping(to: rectImage)!)!
|
|
22
|
+
let imageCrop: UIImage = UIImage(cgImage: imageRef, scale: 0.5, orientation: image.imageOrientation)
|
|
23
|
+
return imageCrop
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static func convertImageToBase64(image: UIImage) -> String {
|
|
27
|
+
let imageData = image.pngData()!
|
|
28
|
+
return imageData.base64EncodedString()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static func rgbDataFromBuffer(_ buffer: CVPixelBuffer) -> Data? {
|
|
32
|
+
let byteCount = batchSize * inputWidth * inputHeight * inputChannels
|
|
33
|
+
CVPixelBufferLockBaseAddress(buffer, .readOnly)
|
|
34
|
+
defer {
|
|
35
|
+
CVPixelBufferUnlockBaseAddress(buffer, .readOnly)
|
|
36
|
+
}
|
|
37
|
+
guard let sourceData = CVPixelBufferGetBaseAddress(buffer) else {
|
|
38
|
+
return nil
|
|
39
|
+
}
|
|
85
40
|
|
|
86
|
-
|
|
87
|
-
|
|
41
|
+
let width = CVPixelBufferGetWidth(buffer)
|
|
42
|
+
let height = CVPixelBufferGetHeight(buffer)
|
|
43
|
+
let sourceBytesPerRow = CVPixelBufferGetBytesPerRow(buffer)
|
|
44
|
+
let destinationChannelCount = 3
|
|
45
|
+
let destinationBytesPerRow = destinationChannelCount * width
|
|
88
46
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// "height": frameRect.height,
|
|
94
|
-
// "boundingCenterX": frameRect.midX,
|
|
95
|
-
// "boundingCenterY": frameRect.midY
|
|
96
|
-
// ]
|
|
97
|
-
// }
|
|
47
|
+
var sourceBuffer = vImage_Buffer(data: sourceData,
|
|
48
|
+
height: vImagePixelCount(height),
|
|
49
|
+
width: vImagePixelCount(width),
|
|
50
|
+
rowBytes: sourceBytesPerRow)
|
|
98
51
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return imageCrop
|
|
52
|
+
guard let destinationData = malloc(height * destinationBytesPerRow) else {
|
|
53
|
+
print("Error: out of memory")
|
|
54
|
+
return nil
|
|
103
55
|
}
|
|
104
56
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return imageData.base64EncodedString()
|
|
57
|
+
defer {
|
|
58
|
+
free(destinationData)
|
|
108
59
|
}
|
|
109
60
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
height: vImagePixelCount(height),
|
|
128
|
-
width: vImagePixelCount(width),
|
|
129
|
-
rowBytes: sourceBytesPerRow)
|
|
130
|
-
|
|
131
|
-
guard let destinationData = malloc(height * destinationBytesPerRow) else {
|
|
132
|
-
print("Error: out of memory")
|
|
133
|
-
return nil
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
defer {
|
|
137
|
-
free(destinationData)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
var destinationBuffer = vImage_Buffer(data: destinationData,
|
|
141
|
-
height: vImagePixelCount(height),
|
|
142
|
-
width: vImagePixelCount(width),
|
|
143
|
-
rowBytes: destinationBytesPerRow)
|
|
144
|
-
|
|
145
|
-
let pixelBufferFormat = CVPixelBufferGetPixelFormatType(buffer)
|
|
146
|
-
|
|
147
|
-
switch (pixelBufferFormat) {
|
|
148
|
-
case kCVPixelFormatType_32BGRA:
|
|
149
|
-
vImageConvert_BGRA8888toRGB888(&sourceBuffer, &destinationBuffer, UInt32(kvImageNoFlags))
|
|
150
|
-
case kCVPixelFormatType_32ARGB:
|
|
151
|
-
vImageConvert_ARGB8888toRGB888(&sourceBuffer, &destinationBuffer, UInt32(kvImageNoFlags))
|
|
152
|
-
case kCVPixelFormatType_32RGBA:
|
|
153
|
-
vImageConvert_RGBA8888toRGB888(&sourceBuffer, &destinationBuffer, UInt32(kvImageNoFlags))
|
|
154
|
-
default:
|
|
155
|
-
// Unknown pixel format.
|
|
156
|
-
return nil
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
let byteData = Data(bytes: destinationBuffer.data, count: destinationBuffer.rowBytes * height)
|
|
160
|
-
let bytes = Array<UInt8>(unsafeData: byteData)!
|
|
161
|
-
var floats = [Float]()
|
|
162
|
-
for i in 0..<bytes.count {
|
|
163
|
-
floats.append(Float(bytes[i]) / 255.0)
|
|
164
|
-
}
|
|
165
|
-
return Data(copyingBufferOf: floats)
|
|
61
|
+
var destinationBuffer = vImage_Buffer(data: destinationData,
|
|
62
|
+
height: vImagePixelCount(height),
|
|
63
|
+
width: vImagePixelCount(width),
|
|
64
|
+
rowBytes: destinationBytesPerRow)
|
|
65
|
+
|
|
66
|
+
let pixelBufferFormat = CVPixelBufferGetPixelFormatType(buffer)
|
|
67
|
+
|
|
68
|
+
switch (pixelBufferFormat) {
|
|
69
|
+
case kCVPixelFormatType_32BGRA:
|
|
70
|
+
vImageConvert_BGRA8888toRGB888(&sourceBuffer, &destinationBuffer, UInt32(kvImageNoFlags))
|
|
71
|
+
case kCVPixelFormatType_32ARGB:
|
|
72
|
+
vImageConvert_ARGB8888toRGB888(&sourceBuffer, &destinationBuffer, UInt32(kvImageNoFlags))
|
|
73
|
+
case kCVPixelFormatType_32RGBA:
|
|
74
|
+
vImageConvert_RGBA8888toRGB888(&sourceBuffer, &destinationBuffer, UInt32(kvImageNoFlags))
|
|
75
|
+
default:
|
|
76
|
+
// Unknown pixel format.
|
|
77
|
+
return nil
|
|
166
78
|
}
|
|
167
79
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return nil
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
|
177
|
-
let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!)
|
|
178
|
-
|
|
179
|
-
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
|
|
180
|
-
let context = CGContext(data: pixelData, width: size, height: size, bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
|
|
181
|
-
|
|
182
|
-
context?.translateBy(x: 0, y: CGFloat(size))
|
|
183
|
-
context?.scaleBy(x: 1.0, y: -1.0)
|
|
184
|
-
|
|
185
|
-
UIGraphicsPushContext(context!)
|
|
186
|
-
image.draw(in: CGRect(x: 0, y: 0, width: size, height: size))
|
|
187
|
-
UIGraphicsPopContext()
|
|
188
|
-
CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
|
189
|
-
return pixelBuffer
|
|
80
|
+
let byteData = Data(bytes: destinationBuffer.data, count: destinationBuffer.rowBytes * height)
|
|
81
|
+
let bytes = Array<UInt8>(unsafeData: byteData)!
|
|
82
|
+
var floats = [Float]()
|
|
83
|
+
for i in 0..<bytes.count {
|
|
84
|
+
floats.append(Float(bytes[i]) / 255.0)
|
|
190
85
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
let ciimage = CIImage(cvPixelBuffer: imageBuffer)
|
|
202
|
-
let context = CIContext(options: nil)
|
|
203
|
-
let cgImage = context.createCGImage(ciimage, from: ciimage.extent)!
|
|
204
|
-
|
|
205
|
-
if (!rectImage.isNull) {
|
|
206
|
-
let imageRef: CGImage = cgImage.cropping(to: rectImage)!
|
|
207
|
-
let imageCrop: UIImage = UIImage(cgImage: imageRef, scale: 0.5, orientation: orientation)
|
|
208
|
-
return imageCrop
|
|
209
|
-
} else {
|
|
210
|
-
return nil
|
|
211
|
-
}
|
|
86
|
+
return Data(copyingBufferOf: floats)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static func uiImageToPixelBuffer(image: UIImage, size: Int) -> CVPixelBuffer? {
|
|
90
|
+
let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
|
|
91
|
+
var pixelBuffer : CVPixelBuffer?
|
|
92
|
+
let status = CVPixelBufferCreate(kCFAllocatorDefault, size, size, kCVPixelFormatType_32ARGB, attrs, &pixelBuffer)
|
|
93
|
+
guard (status == kCVReturnSuccess) else {
|
|
94
|
+
return nil
|
|
212
95
|
}
|
|
213
96
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
97
|
+
CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
|
98
|
+
let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!)
|
|
99
|
+
|
|
100
|
+
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
|
|
101
|
+
let context = CGContext(data: pixelData, width: size, height: size, bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
|
|
102
|
+
|
|
103
|
+
context?.translateBy(x: 0, y: CGFloat(size))
|
|
104
|
+
context?.scaleBy(x: 1.0, y: -1.0)
|
|
105
|
+
|
|
106
|
+
UIGraphicsPushContext(context!)
|
|
107
|
+
image.draw(in: CGRect(x: 0, y: 0, width: size, height: size))
|
|
108
|
+
UIGraphicsPopContext()
|
|
109
|
+
CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
|
110
|
+
return pixelBuffer
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static func getImageFaceFromBuffer(from sampleBuffer: CMSampleBuffer, rectImage: CGRect, orientation: UIImage.Orientation) -> CVPixelBuffer? {
|
|
114
|
+
autoreleasepool {
|
|
115
|
+
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
|
|
116
|
+
let ciimage = CIImage(cvPixelBuffer: imageBuffer!)
|
|
117
|
+
let context = CIContext(options: nil)
|
|
118
|
+
let cgImage = context.createCGImage(ciimage, from: ciimage.extent)!
|
|
119
|
+
|
|
120
|
+
let imageRef: CGImage = cgImage.cropping(to: rectImage)!
|
|
121
|
+
let imageCrop: UIImage = UIImage(cgImage: imageRef, scale: 0.5, orientation: orientation)
|
|
122
|
+
return uiImageToPixelBuffer(image: imageCrop, size: inputWidth)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
242
125
|
}
|
|
243
126
|
|
|
244
127
|
// MARK: - Extensions
|
|
245
128
|
extension Data {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
129
|
+
// Creates a new buffer by copying the buffer pointer of the given array.
|
|
130
|
+
init<T>(copyingBufferOf array: [T]) {
|
|
131
|
+
self = array.withUnsafeBufferPointer(Data.init)
|
|
132
|
+
}
|
|
250
133
|
}
|
|
251
134
|
|
|
252
135
|
extension Array {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
136
|
+
// Creates a new array from the bytes of the given unsafe data.
|
|
137
|
+
init?(unsafeData: Data) {
|
|
138
|
+
guard unsafeData.count % MemoryLayout<Element>.stride == 0 else { return nil }
|
|
139
|
+
self = unsafeData.withUnsafeBytes { .init($0.bindMemory(to: Element.self)) }
|
|
140
|
+
}
|
|
258
141
|
}
|