반응형
SwiftUI로 나를 닮은 앱 만들기
자격증 공부하던 도중 문득 나를 닮은 동물은 뭘까? 싶어 간단하게 구현 해볼까? 해서 이 프로젝트를 시작하게 됐습니다. 이번 시간에는
카메라를 구현해서 정상적으로 얼굴이 감지 되는지까지의 코드를 작성 해보겠습니다.
준비물
1. Xcode
2. 실제 실행 해볼 iphone
3. The Oxford-IIIT Pet Dataset
4. 엄청나게 소중한 구글
IOS 카메라 구현 하기
이번엔 카메라가 재대로 작동하고 있는지 기능에 따라 파일을 만들어 보겠습니다.
Privacy - Camera Usage Description 생성하기
프로젝트를 클릭하여 Info 탭에서 Privacy - Camera Usage Description을 찾아서 생성해주시면 됩니다.
다 구현해도 이거 추가 안 하면 카메라 안 나옵니다. 중요하니 프로젝트 생성해서 제일 처음으로 해주세요.
CameraManager.swift 파일 생성
import AVFoundation
import Vision
import UIKit
class CameraManager: NSObject, ObservableObject {
@Published var isRecognizing: Bool = false
@Published var detectedFacesCount: Int = 0
let captureSession = AVCaptureSession()
private var detectionRequest: VNDetectFaceRectanglesRequest?
private var detectionSequenceHandler = VNSequenceRequestHandler()
override init() {
super.init()
setupCaptureSession()
setupVision()
}
private func setupVision() {
detectionRequest = VNDetectFaceRectanglesRequest { [weak self] request, error in
guard let results = request.results as? [VNFaceObservation] else { return }
DispatchQueue.main.async {
self?.detectedFacesCount = results.count
self?.isRecognizing = results.count > 0
}
}
}
private func setupCaptureSession() {
guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front) else {
print("전면 카메라를 찾을 수 없습니다.")
return
}
do {
let input = try AVCaptureDeviceInput(device: camera)
if captureSession.canAddInput(input) {
captureSession.addInput(input)
}
} catch {
print("카메라 설정 중 오류 발생: \(error.localizedDescription)")
}
}
func startSession() {
DispatchQueue.global(qos: .background).async {
self.captureSession.startRunning()
}
}
func stopSession() {
captureSession.stopRunning()
}
func detectFaces(in image: CVPixelBuffer) {
guard let request = detectionRequest else { return }
do {
try detectionSequenceHandler.perform([request], on: image, orientation: .right)
} catch {
print("얼굴 감지 실패: \(error.localizedDescription)")
}
}
}
코드 설명
- 클래스 구조:
- NSObject를 상속받고 ObservableObject 프로토콜을 준수합니다.
- AVFoundation, Vision, UIKit 프레임워크를 사용합니다.
- 주요 프로퍼티:
- isRecognizing: 얼굴 인식 중인지 여부 (Published)
- detectedFacesCount: 감지된 얼굴 수 (Published)
- captureSession: 카메라 캡처 세션
- detectionRequest: 얼굴 감지 요청
- detectionSequenceHandler: 비전 요청 처리기
- 초기화 및 설정:
- init(): 카메라 세션과 비전 설정을 초기화합니다.
- setupVision(): 얼굴 감지 요청을 설정합니다.
- setupCaptureSession(): 전면 카메라를 사용하여 캡처 세션을 설정합니다.
- 주요 메서드:
- startSession(): 백그라운드 큐에서 캡처 세션을 시작합니다.
- stopSession(): 캡처 세션을 중지합니다.
- detectFaces(in:): 주어진 이미지에서 얼굴을 감지합니다.
- 얼굴 감지 로직:
- VNDetectFaceRectanglesRequest를 사용하여 얼굴을 감지합니다.
- 감지 결과를 메인 큐에서 detectedFacesCount와 isRecognizing 프로퍼티에 반영합니다.
- 오류 처리:
- 카메라 설정 및 얼굴 감지 과정에서 발생할 수 있는 오류를 처리합니다.
카메라를 통한 실시간 얼굴 감지 기능을 구현하는 데 사용될 수 있으며, ObservableObject를 통해 UI와 쉽게 연동될 수 있습니다.
CameraView.swift 파일 생성
import SwiftUI
import AVFoundation
import Vision
struct CameraView: UIViewRepresentable {
@ObservedObject var cameraManager: CameraManager
class Coordinator: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
var parent: CameraView
init(_ parent: CameraView) {
self.parent = parent
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
self.parent.cameraManager.detectFaces(in: pixelBuffer)
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: UIScreen.main.bounds)
let previewLayer = AVCaptureVideoPreviewLayer(session: cameraManager.captureSession)
previewLayer.frame = view.bounds
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(context.coordinator, queue: DispatchQueue(label: "videoQueue"))
if cameraManager.captureSession.canAddOutput(videoOutput) {
cameraManager.captureSession.addOutput(videoOutput)
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
코드 설명
- 구조체 구조:
- UIViewRepresentable 프로토콜을 준수하여 UIKit 뷰를 SwiftUI에서 사용할 수 있게 합니다.
- SwiftUI, AVFoundation, Vision 프레임워크를 사용합니다.
- 프로퍼티:
- cameraManager: CameraManager 인스턴스를 관찰 가능한 객체로 사용합니다.
- Coordinator 클래스:
- AVCaptureVideoDataOutputSampleBufferDelegate 프로토콜을 준수합니다.
- 카메라로부터 받은 프레임을 처리하고 얼굴 감지를 수행합니다.
- 주요 메서드:
- makeCoordinator(): Coordinator 인스턴스를 생성합니다.
- makeUIView(context:): UIKit 뷰를 생성하고 설정합니다.
- updateUIView(_:context:): 뷰 업데이트 시 호출되지만 현재는 구현되지 않았습니다.
- 카메라 프리뷰 설정:
- AVCaptureVideoPreviewLayer를 사용하여 카메라 프리뷰를 표시합니다.
- 프리뷰 레이어의 크기와 비디오 그래비티를 설정합니다.
- 비디오 출력 설정:
- AVCaptureVideoDataOutput을 설정하여 비디오 프레임을 캡처합니다.
- 캡처된 프레임은 Coordinator의 captureOutput 메서드로 전달됩니다.
- 얼굴 감지 처리:
- 캡처된 각 프레임에 대해 CameraManager의 detectFaces(in:) 메서드를 호출하여 얼굴을 감지합니다.
위 코드 파일은 카메라 프리뷰를 표시하고, 실시간으로 얼굴을 감지하는 기능을 구현합니다.CameraManager와 연동하여 작동합니다.
ContentView.swiftUI 파일 생성
import SwiftUI
struct ContentView: View {
@StateObject private var cameraManager = CameraManager()
var body: some View {
ZStack {
CameraView(cameraManager: cameraManager)
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Text("감지된 얼굴: \(cameraManager.detectedFacesCount)")
.foregroundColor(.white)
.padding()
.background(Color.black.opacity(0.7))
.cornerRadius(10)
.padding(.bottom)
}
}
.onAppear {
cameraManager.startSession()
}
.onDisappear {
cameraManager.stopSession()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
코드 설명
- 구조체 구조:
- View 프로토콜을 준수하여 SwiftUI 뷰를 정의합니다.
- 프로퍼티:
- cameraManager: CameraManager 인스턴스를 @StateObject로 선언하여 뷰의 생명주기 동안 유지합니다.
- 뷰 구성:
- ZStack을 사용하여 카메라 뷰와 텍스트 오버레이를 겹쳐 표시합니다.
- CameraView를 전체 화면으로 표시합니다.
- VStack을 사용하여 화면 하단에 감지된 얼굴 수를 표시합니다.
- 텍스트 스타일링:
- 감지된 얼굴 수를 표시하는 텍스트에 배경색, 모서리 둥글기, 패딩 등을 적용하여 가독성을 높입니다.
- 생명주기 관리:
- onAppear 수정자를 사용하여 뷰가 나타날 때 카메라 세션을 시작합니다.
- onDisappear 수정자를 사용하여 뷰가 사라질 때 카메라 세션을 중지합니다.
- 프리뷰:
- ContentView_Previews 구조체를 사용하여 SwiftUI 프리뷰를 제공합니다.
CameraManager와 CameraView를 사용하여 실시간 카메라 피드를 표시하고, 감지된 얼굴의 수를 화면에 오버레이로 표시합니다.
반응형
'개발하기 > SwiftUI' 카테고리의 다른 글
Xcode에서 Pod init해결 방법 (2) | 2024.12.06 |
---|---|
error: unable to read property list from file: (1) | 2024.12.03 |
[2탄]The Oxford-IIIT Pet Dataset를 이용해 닮은 동물 ios 앱 만들기 (2) | 2024.09.30 |
Xcode 없이 MacOS 앱 실행하기: 개발자를 위한 간단 가이드 (8) | 2024.09.25 |
Xcode에서 SwiftUI를 사용하여 Mysql 연결하는 방법 (10) | 2024.09.20 |