余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

iOS AI相机App开发教程,01 基础相机功能实现

xiyangw 2022-12-03 13:29 30 浏览 0 评论

SwiftUI 基础

首先,如果你是刚刚开始学习SwiftUI的,那么你可以先学习一下基础的SwiftUI。
这方面的教程网上有很多,这里就不介绍了,我们直接从实现相机功能开始入手。

相机拍照

拍照protocol和Events

定义相机拍照协议(protocol),所有相机相关的View需要实现该协议来处理结果。
定义一个ObservableObject类型,用来控制相机拍照和翻转。

iOS AI相机App开发教程,01 基础相机功能实现


// 拍照协议
public protocol CameraFxImage {
    // 拍照完成方法
    // image: 照片 UIImage 对象
    mutating func didImageOk(_ image: UIImage)

    // 执行特效方法
    // fx:特效名称
    mutating func doFx(_ fx: String)
}

// 拍照Events
public class UserEvents: ObservableObject {
    // 触发相机拍照
    @Published public var didAskToCapturePhoto = false
    // 触发相机翻转
    @Published public var didAskToRotateCamera = false
    
    public init() {
        
    }
}

BBMetalImage

需要先使用 CocosPods 安装 BBMetalImage 具体方法加不在这里赘述了。
通过 BBMetalImage 库的 BBMetalCamera 来实现相机和基础滤镜功能。

相机预览 CameraPhotoFilterView

通过实现 UIViewController 和 UIViewControllerRepresentable 协议,创建相机预览SwiftUI View
详细代码可以参考:
MagicCamera/SwiftUICam/CameraPhotoFilterVC.swift

CameraPhotoFilterVC 实现 UIViewController

// 引入依赖的库
import AVFoundation
import BBMetalImage

class CameraPhotoFilterVC: UIViewController {
    // 相机
    private var camera: BBMetalCamera!
    // 预览View
    private var metalView: BBMetalView!
    // 相机拍照协议
    public var delegateFx: CameraFxImage?
    // 相机方向
    public var position: AVCaptureDevice.Position = .front
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // view.backgroundColor = .white
        
        var smooth = Float(0.5)
        var brightness = Float(0.01)
        var preset = AVCaptureSession.Preset.photo
        ...
        
        // 创建相机
        camera = BBMetalCamera(sessionPreset: preset, position: position)
        if camera == nil {
            camera = BBMetalCamera(sessionPreset: .high, position: position)
        }
        
        let x: CGFloat = 0
        let width: CGFloat = view.bounds.width
        let height: CGFloat = min(width*4/3, view.bounds.height*2/3)
        
        // 创建预览
        metalView = BBMetalView(frame: CGRect(x: x, y: 0, width: width, height: height))
        metalView.setContentHuggingPriority(.defaultLow, for: .horizontal)
        metalView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        view.addSubview(metalView)
        
        camera.canTakePhoto = true
        camera.photoDelegate = self
        
        // 将滤镜添加到相机预览
        camera
            .add(consumer: BBMetalBeautyFilter(distanceNormalizationFactor: 4, stepOffset: 4, edgeStrength: 1, smoothDegree: smooth))
            .add(consumer: BBMetalBrightnessFilter(brightness: brightness))
            .add(consumer: metalView)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 启动相机预览
        camera.start()
        metalView.isHidden = false
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // 停止相机预览
        camera.stop()
    }
    
    public func switchCameraPosition()  {
        // 翻转相机
        camera.switchCameraPosition()
    }
    
    public func takePhoto()  {
        // 拍照
        metalView.isHidden = true
        camera.takePhoto()
    }
}

// 实现 BBMetalCameraPhotoDelegate,处理拍照结果
extension CameraPhotoFilterVC: BBMetalCameraPhotoDelegate {
    func camera(_ camera: BBMetalCamera, didOutput texture: MTLTexture) {
        // In main thread
        ...

        // 添加滤镜
        let brightness = BBMetalBrightnessFilter(brightness: bright)
        let imageSource = BBMetalStaticImageSource(image: texture.bb_image!)
        // 设置滤镜链,并设置滤镜同步执行
        imageSource.add(consumer: BBMetalBeautyFilter(distanceNormalizationFactor: 4, stepOffset: 4, edgeStrength: 1, smoothDegree: smooth))
            .add(consumer: brightness)
            .runSynchronously = true

        // 开始处理
        imageSource.transmitTexture()
        // 返回处理后结果
        guard let filteredImage = brightness.outputTexture?.bb_image else { return  }
        
        metalView.isHidden = false
        DispatchQueue.main.async {
            // 完成后调用代理方法,返回照片
            self.delegateFx?.didImageOk(filteredImage)
        }
    }
}

CameraPhotoFilterView 实现 UIViewControllerRepresentable


struct CameraPhotoFilterView: UIViewControllerRepresentable {
    @ObservedObject var events: UserEvents
    private var level: Int
    private var position: AVCaptureDevice.Position = .front
    private var delegateFx: CameraFxImage?
    
    typealias UIViewControllerType = CameraPhotoFilterVC
    func makeUIViewController(context: Context) -> CameraPhotoFilterVC {
        // 创建 CameraPhotoFilterVC 实例
        let vc = CameraPhotoFilterVC()
        vc.delegateFx = self.delegateFx
        vc.level = self.level
        vc.position = self.position
        return vc
    }
    
    // 更新时调用
    func updateUIViewController(_ cameraController: CameraPhotoFilterVC, context: Context) {
        if events.didAskToCapturePhoto {
            // 开始拍照
            events.didAskToCapturePhoto = false
            cameraController.takePhoto()
        }
        
        if events.didAskToRotateCamera {
            // 开始翻转相机
            events.didAskToRotateCamera = false
            cameraController.switchCameraPosition()
        }
    }
    
    public init(events: UserEvents, delegateFx: CameraFxImage?, level: Int = 1, position: AVCaptureDevice.Position = .front) {
        ...
    }
}

拍照界面

拍照界面代码如下:需要定义拍照Events,拍照协议,相机方向等参数
使用 ZStack 把 CameraPhotoFilterView 放在底层,在预览界面上方放置拍照按钮等
详细代码可以参考:
MagicCamera/SwiftUICam/LiveCameraFilterView.swift

struct LiveCameraFilterView: View {
    // 拍照Events
    @ObservedObject var events: UserEvents
    // 拍照协议
    var delegateFx: CameraFxImage?
    // 相机方向
    var position: AVCaptureDevice.Position = .front
    
    // 初始化参数
    public init(events: UserEvents, delegateFx: CameraFxImage?, position: AVCaptureDevice.Position = .front) {
        ...
    }

    var body: some View {
        ZStack {
            // 相机预览 CameraPhotoFilterView
            CameraPhotoFilterView(events:events, delegateFx: delegateFx, level: level, position: position)
            // 在预览上方显示其他界面,如拍照按钮等
            VStack {
                HStack {
                    Spacer()
                    // 拍照按钮
                    Button(action: {
                        weakself.events.didAskToCapturePhoto = true
                    }, label: {
                        ...
                    }).disabled(takeing)
                    Spacer()
                    // 翻转按钮
                    Button(action: {
                        weakself.events.didAskToRotateCamera = true
                    }, label: {
                        ...
                    }).disabled(takeing)
                    Spacer()
                }
                ...
            }

        }
    }
}

使用拍照

在需要拍照的页面上使用 LiveCameraFilterView, 并实现 CameraFxImage 协议
详细代码可以参考:
MagicCamera/Cameras/BeautyCameraView.swift

相关推荐

前后端分离 Vue + NodeJS(Koa) + MongoDB实践

作者:前端藏经阁转发链接:https://www.yuque.com/xwifrr/gr8qaw/vr51p4写在前面闲来无事,试了一下Koa,第一次搞感觉还不错,这个项目比较基础但还是比较完整了,...

MongoDB 集群如何工作?

一、什么是“MongoDB”?“MongoDB”是一个开源文档数据库,也是领先的“NoSQL”数据库,分别用“C++”“编程语言”编写,使用带有“Schema”的各种类似JSON的文档,是也分别被认为...

三部搭建mongo,和mongo UI界面

三步搭建mongo,和mongoUI界面安装首先你需要先有一个docker的环境检查你的到docker版本docker--versionDockerversion18.03.1-ce,b...

Mongodb 高可用落地方案

此落地方案,用于实现高可用。复制集这里部署相关的复制集,用于实现MongoDB的高可用。介绍MongoDB复制集用于提供相关的数据副本,当发生硬件或者服务中断的时候,将会从副本中恢复数据,并进行自动...

一次线上事故,我顿悟了MongoDB的精髓

大家好,我是哪吒,最近项目在使用MongoDB作为图片和文档的存储数据库,为啥不直接存MySQL里,还要搭个MongoDB集群,麻不麻烦?让我们一起,一探究竟,继续学习MongoDB分片的理论与实践,...

IDEA中安装MongoDB插件-再也无要nosql manager for mongodb

大家都知道MongoDB数据库作为典型的非关系型数据库被广泛使用,但基于MongoDB的可视化管理工具-nosqlmanagerformongodb也被用的较多,但此软件收费,所以国内的破解一般...

数据库监控软件Lepus安装部署详解

Lepus安装部署一、软件介绍Lepus是一套开源的数据库监控平台,目前已经支持MySQL、Oracle、SQLServer、MongoDB、Redis等数据库的基本监控和告警(MySQL已经支持复...

YAPI:从0搭建API文档管理工具

背景最近在找一款API文档管理工具,之前有用过Swagger、APIManager、Confluence,现在用的还是Confluence。我个人一直不喜欢用Swagger,感觉“代码即文档”,让代...

Mac安装使用MongoDB

下载MongoDB包:https://www.mongodb.com/download-center解压mongodb包手动解压到/usr/local/mongodb文件夹配置Mac环境变量打开环境...

保证数据安全,不可不知道的MongoDB备份与恢复

大家在项目中如果使用MongoDB作为NOsql数据库进行存储,那一定涉及到数据的备份与恢复,下面给大家介绍下:MongoDB数据备份方法在MongoDB中我们使用mongodump命令来备...

MongoDB数据备份、还原脚本和定时任务脚本

备注:mongodump和mongorestore命令需要在MongoDB的安装目录bin下备份脚本备份格式/usr/local/mongodb/bin/mongodump -h ...

等保2.0测评:mongoDB数据库

一、MongoDB介绍MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之间的产...

MongoDB入门实操《一》

什么是MongoDBMongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之...

Python安装PyMongo的方法详细介绍

欢迎点击右上角关注小编,除了分享技术文章之外还有很多福利,私信学习资料可以领取包括不限于Python实战演练、PDF电子文档、面试集锦、学习资料等。前言本文主要给大家介绍的是关于安装PyMongo的...

第四篇:linux系统中mongodb的配置

建议使用普通用户进行以下操作。1、切换到普通用户odysee。2、准备mongodb安装包,自行去官网下载。3、解压安装包并重命名为mongodb4.04、配置mongodbcdmongod...

取消回复欢迎 发表评论: