您是否想在 iOS 应用中几秒钟内使用功能齐全的摄像头?您是否想在这同一摄像头上进行几秒钟的 CoreML 图片识别?Lumina 正在为此提供帮助。
Cameras 常在 iOS 应用中使用,iOS 11 中添加的 CoreML
和 Vision
引发了大量应用程序的出现,这些应用程序从图片中进行实时物体识别——无论是从静止图片还是通过摄像头流。
编写 AVFoundation
代码可能很有趣,有时可能令人感兴趣。Lumina
给您提供了一个跳过编写 AVFoundation
代码的机会,并提供您所需的工具来处理您已经构建的摄像头。
Lumina 可以
- 捕获静态图片
- 捕获视频
- 捕获实时照片
- 从双摄像头系统中捕获静态图片的深度数据
- 将视频帧流式传输到代理
- 扫描任何 QR 或条形码并输出其元数据
- 检测人脸及其位置
- 使用任何 CoreML 兼容模型从摄像头流中流式传输对象预测
目录
要求
- Xcode 10.0+(通过加载 Swift 4 工具链)
- iOS 11.0
- Swift 5.0
背景
David Okun 在图像处理方面有经验,他认为有一款可以流图像、拍照和录视频的相机模块是一件好事,还有一个模块可以连接CoreML模型,并将对象预测和视频帧一起流回用户。
贡献
请查阅贡献文件!
接受PR。
小贴士:修改README时,请遵守standard-readme规范。
安装
CocoaPods
您可以使用CocoaPods 将 Lumina
添加到您的 Podfile
以进行安装。
platform :ios, '12.0'
use_frameworks!
target 'MyApp' do
pod 'Lumina'
end
Carthage
您可以通过将Lumina
添加到您的Cartfile
来使用Carthage 进行安装。
github "dokun1/Lumina"
Swift Package Manager
注意:由于不支持需要UIKit的框架,Lumina当前无法与Swift包管理器一起构建。尽管如此,随着SPM的发展,Lumina将准备好支持它!
您可以使用Swift包管理器通过向您的Package.swift
文件添加正确描述来安装Lumina
。
import PackageDescription
let package = Package(
name: "YOUR_PROJECT_NAME",
targets: [],
dependencies: [
.Package(url: "https://github.com/dokun1/Lumina.git", majorVersion: 1)
]
)
注意:随着Swift包管理器的持续发展,请在此查看其文档。
手动构建
克隆或下载此存储库,并使用提供的workSPACE构建用于您自己的任何应用的库版本。
使用
注意:此存储库包含一个示例应用。该应用旨在演示库的完整功能集。我们建议您尝试该应用。
初始化
考虑到Lumina的主要用途是呈现一个ViewController
,以下是一个在模板ViewController
中添加内容的示例:
import Lumina
我们建议在您的ViewController的生命周期中尽早使用以下方式创建相机的单个实例:
let camera = LuminaViewController()
呈现Lumina
如下:
present(camera, animated: true, completion:nil)
请记得在您的Info.plist
文件中添加对Privacy - Camera Usage Description
和Privacy - Microphone Usage Description
的描述,以确保正确处理系统权限。
日志记录
注意:虽然 Lumina 使用 MIT 许可证进行授权,但 swift-log 使用 Apache 2.0 许可证。许可证的副本也已包含在源代码中。
LuminaViewController.loggingLevel = .verbose
- 无
- 信息
- 通知
- 警告
- 危机
- 错误
- 调试
- 跟踪
camera.position = .front // could also be .back
camera.recordsVideo = true // if this is set, streamFrames and streamingModel are invalid
camera.streamFrames = true // could also be false
camera.textPrompt = "This is how to test the text prompt view" // assigning an empty string will make the view fade away
camera.trackMetadata = true // could also be false
camera.resolution = .highest // follows an enum
camera.captureLivePhotos = true // for this to work, .resolution must be set to .photo
camera.captureDepthData = true // for this to work, .resolution must be set to .photo, .medium1280x720, or .vga640x480
camera.streamDepthData = true // for this to work, .resolution must be set to .photo, .medium1280x720, or .vga640x480
camera.frameRate = 60 // can be any number, defaults to 30 if selection cannot be loaded
camera.maxZoomScale = 5.0 // not setting this defaults to the highest zoom scale for any given camera device
注意:此功能仅适用于 iOS 11.0 及以上版本。
camera.streamingModels = [LuminaModel(model: MobileNet().model, type: "MobileNet"), LuminaModel(model: SqueezeNet().model, type: "SqueezeNet")]
camera.delegate = self
func dismissed(controller: LuminaViewController) {
// here you can call controller.dismiss(animated: true, completion:nil)
}
func captured(stillImage: UIImage, livePhotoAt: URL?, depthData: Any?, from controller: LuminaViewController) {
controller.dismiss(animated: true) {
// still images always come back through this function, but live photos and depth data are returned here as well for a given still image
// depth data must be manually cast to AVDepthData, as AVDepthData is only available in iOS 11.0 or higher.
}
func captured(videoAt: URL, from controller: LuminaViewController) {
// here you can load the video file from the URL, which is located in NSTemporaryDirectory()
}
注意:值得注意的是,如果您在使用 Lumina 的视频录制模式下,无法流式传输帧。为了启用帧流传输,您必须将 .recordsVideo
设置为 false,将 .streamFrames
设置为 true。
func streamed(videoFrame: UIImage, from controller: LuminaViewController) {
// here you can take the image called videoFrame and handle it however you'd like
}
func streamed(depthData: Any, from controller: LuminaViewController) {
// here you can take the depth data and handle it however you'd like
// NB: you must cast the object to AVDepthData manually. It is returned as Any to maintain backwards compatibility with iOS 10.0
}
处理从相机检测和流出的元数据,实现以下功能:
func detected(metadata: [Any], from controller: LuminaViewController) {
// here you can take the metadata and handle it however you'd like
// you must find the right kind of data to downcast from, whether it is of a barcode, qr code, or face detection
}
处理用户点击屏幕(除按钮外)的操作,实现以下功能:
func tapped(from controller: LuminaViewController, at: CGPoint) {
// here you can take the position of the tap and handle it however you'd like
// default behavior for a tap is to focus on tapped point
}
处理“CoreML”模型及其预测与每帧视频一起流式传输,实现以下功能:
func streamed(videoFrame: UIImage, with predictions: [LuminaRecognitionResult]?, from controller: LuminaViewController) {
if #available(iOS 11.0, *) {
guard let predicted = predictions else {
return
}
var resultString = String()
for prediction in predicted {
guard let values = prediction.predictions else {
continue
}
guard let bestPrediction = values.first else {
continue
}
resultString.append("\(String(describing: prediction.type)): \(bestPrediction.name)" + "\r\n")
}
controller.textPrompt = resultString
} else {
print("CoreML not available in iOS 10.0")
}
}
请注意,这返回与检测到结果相关的类类型表示。上面的示例还使用了Lumina的内置文本提示机制。
更改用户界面
为了适配用户界面以适应您的需求,您可以调用以下方法在LuminaViewController
上设置按钮的可见性
camera.setCancelButton(visible: Bool)
camera.setShutterButton(visible: Bool)
camera.setSwitchButton(visible: Bool)
camera.setTorchButton(visible: Bool)
默认情况下,所有按钮都是可见的。
维护者
授权许可
MIT © 2019 David Okun