스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
앱에서 이미지의 피사체 분리하기
앱의 배경에서 이미지의 피사체를 쉽게 가져오는 방법을 알아보세요. 주요 피사체를 분리하거나 VisionKit을 사용하여 지정된 지점에서 피사체에 액세스하는 방법을 확인하세요. 또한 Vision을 사용하여 피사체를 분리한 후 이를 Core Image와 같은 하위 프레임워크와 결합하여 재미있는 이미지 효과와 더 복잡한 합성 파이프라인을 만드는 방법도 알려드립니다. VisionKit의 최신 업데이트에 대한 자세한 내용은 'VisionKit의 새로운 기능'을 확인하세요. 이미지의 사람 세그먼테이션에 대한 자세한 내용은 WWDC23의 'Vision에서 3D 신체 포즈 및 사람 세그먼테이션 살펴보기'를 시청하세요.
리소스
관련 비디오
WWDC23
-
다운로드
♪ ♪
안녕하세요, 저는 리지입니다 Apple에서 Visionkit을 담당하는 엔지니어입니다 오늘 제가 말씀드릴 것은 여러분의 앱에 피사체 분리하기 기능을 넣는 방법입니다 피사체 분리하기는 iOS 16에 도입된 기능으로 이를 통해 사용자는 피사체를 선택, 분리한 다음 공유할 수 있죠 먼저 피사체 분리하기의 기본적인 사항을 살펴본 다음 새 VisionKit API를 활용하여 앱에 추가하는 방법을 알아볼게요 마지막으로 제 동료 소미트로가 좀 더 깊이 들어가서 기저에 있는 새 Vision API를 소개할 것입니다
피사체란 무엇일까요? 피사체란 사진의 전경에 위치한 대상체를 말합니다 사람이나 반려동물만이 아니라 건물, 음식, 신발 같은 것도 될 수 있습니다
피사체가 여러 개일 수도 있겠죠 이 커피 세 잔처럼요 중요한 것은 피사체가 꼭 개별 대상체는 아니라는 거죠 이 예시를 보시면 남자와 개가 있는데 둘 다 이미지의 초점이므로 하나의 피사체나 마찬가지입니다 그러면 이 기능을 어떻게 앱에 넣을 수 있을까요? 피사체 분리하기를 앱에 추가하는 API에는 두 가지가 있습니다 VisionKit과 Vision입니다 Visionkit을 사용하면 시스템과 같은 피사체 분리하기를 바로 구현할 수 있습니다 알다시피 피사체 분리하기 UI를 코드 몇 줄만 써서 쉽게 새로 만들 수 있죠 Visionkit은 피사체의 기본적인 정보도 보여 줍니다 그래서 피사체를 활용하는 새로운 방법을 제공할 수 있죠
별도의 프로세스이므로 성능이 향상되지만 이미지 크기에 한계가 있습니다 Vision은 저수준 프레임워크로서 바로 쓸 수 있는 UI가 없습니다 즉, 뷰에 구애받지 않고 더욱 자유롭게 만들 수 있죠
이미지 분석은 프로세스 내에서 이뤄지며 VisionKit처럼 이미지 해상도 제한은 없습니다 결국, 이 API는 고급 이미지 편집 파이프라인에 사용할 수 있죠 예를 들면 Core Image를 사용한다든지요 먼저 VisionKit의 피사체 분리하기 API를 보겠습니다 VisionKit으로 피사체 분리하기를 추가하려면 ImageAnalysisInteraction을 초기화하고 이미지가 포함된 뷰에 추가하면 됩니다 UIImageView가 될 수도 있지만 꼭 그럴 필요는 없습니다 그만큼 간단합니다 이제 이미지는 시스템 피사체 분리하기 상호작용을 하게 됩니다 이와 유사하게 macOS에서는 ImageAnalysisOverlayView를 만들고 그것을 이미지가 들어 있는 NSView의 서브뷰로 추가합니다 선호하는 상호작용 유형을 설정할 수도 있습니다 ImageAnalysisInteraction이나 ImageAnalysisOverlayView에요 어떤 VisionKit 상호작용 유형을 지원할지 선택합니다 상호작용 유형의 초깃값은 .automatic입니다 이것은 시스템 동작을 그대로 따라 하는 거죠 피사체 분리하기, 라이브 텍스트 데이터 감지기가 필요하면 이 유형을 쓰세요 새로운 .imageSubject 유형은 피사체 분리하기만 됩니다 텍스트 상호작용은 원하지 않는 경우에 사용합니다 이런 UI 상호작용에 더해서 Visionkit은 피사체에 프로그램으로 액세스할 수 있죠 ImageAnalysis를 사용해서요 이미지 분석을 하려면 ImageAnalyzer를 생성하고 analyze 함수를 호출합니다 원하는 이미지와 analyzer 설정을 입력하세요 이미지의 피사체 목록에 비동기 엑세스할 수 있습니다 ImageAnalysis의 subjects 프로퍼티를 사용해서요 이것은 이미지와 경계선이 포함된 새 Subject 데이터 구조를 사용하죠 highlightedSubjects의 반환값은 강조된 피사체들입니다 이 예시에서는 아래에 있는 두 피사체가 강조됐습니다 사용자는 길게 눌러서 피사체를 강조할 수 있지만 개발자 여러분도 선택 상태를 바꿀 수 있습니다 코드에서 highlightedSubjects를 업데이트하면요 async subject(at:) 메서드를 써서 피사체를 지점으로 찾을 수 있죠 이 예시에서 이곳을 탭하면 반환값이 가운데 피사체가 됩니다 해당 지점에 피사체가 없다면 이 메서드의 반환값은 nil입니다 결국 피사체 이미지는 두 가지 방법으로 생성할 수 있죠 단일 피사체라면 피사체의 이미지 프로퍼티에 액세스하세요 피사체 여러 개로 이뤄진 이미지가 필요하다면 async image(for:) 메서드를 사용하여 포함하고 싶은 피사체를 보내세요 이 예시에서 아래쪽 두 피사체만 필요하다면 이 메서드를 사용하여 이런 이미지를 생성합니다 데모 프로젝트에서 이 모든 것을 해 보겠습니다 저는 퍼즐 앱을 만들고 있는데요 퍼즐 조각을 드래그하여 퍼즐에 붙이고 싶습니다 하지만 아직 어떤 조각도 분리할 수 없죠 문제를 해결해 봅시다 먼저, 피사체 분리하기 상호작용이 가능해야 합니다 그래야 조각들이 상호작용할 수 있습니다 ImageAnalysisInteraction을 만들면 그렇게 할 수 있죠 그것을 제 뷰에 추가하기만 하면 됩니다
저는 여기서 .imageSubject 상호작용 유형을 썼는데요 라이브 텍스트는 제외하고 싶기 때문입니다
멋지네요! 이제 퍼즐 조각을 선택해서 이렇게 상호작용 할 수 있죠 이 이미지는 어떤 식으로든 사전 처리되지 않았습니다 피사체 분리하기만 쓴 겁니다 퍼즐 조각을 퍼즐에 넣는 것을 담당할 코드를 추가했습니다 이 코드는 퍼즐이 꼭 맞도록 위치까지 조정합니다
이걸로도 아주 좋아 보이지만 제 앱을 훨씬 더 매력적으로 만들고 싶습니다 퍼즐 조각 아래쪽에 그림자 효과를 추가할 생각입니다 퍼즐 위에서 움직일 때 약간의 3D 효과를 주려고요 호버 제스처 핸들러는 이미 있습니다 그림자만 추가하면 됩니다 이미지는 쉽게 편집할 수 없지만 이미지를 겹쳐서 그림자를 만들어 줄 수는 있죠 먼저, Apple Pencil이 피사체 위에 있는지 확인합니다 imageAnalysis.subject(at point:)를 호출해서요 addShadow(for subject:)라는 메서드가 있는데요 피사체의 복사본을 삽입하고 회색으로 바꾸며 원래 피사체 위치와 살짝 어긋나게 합니다 그런 다음 그림자 위에 피사체의 복사본을 추가합니다 그러면 3차원처럼 보이죠 마지막으로, 호버 위치가 피사체와 겹치지 않으면 그림자를 지웁니다
이제 테스트해 보죠
멋지네요, 퍼즐 조각에 그림자 효과가 생깁니다 Apple Pencil이 위에 있으면요
Visionkit을 사용하여 제 앱에 피사체 분리하기를 설정했습니다 또한 몇 줄의 코드로 재미있는 피사체 효과도 추가했죠
이제 제 동료 소미트로가 나와서 새로운 Vision API와 이것을 앱에 통합하는 방법을 알려드릴 겁니다 고마워요, 리지! 안녕하세요, 저는 소미트로입니다 Vision 팀 소속 엔지니어죠 VisionKit API는 피사체 분리를 제일 쉽게 할 수 있는 방법입니다 더 고급 기능이 필요한 앱은 Vision이 도와줄 겁니다 피사체 분리하기는 Vision의 기존 세그멘테이션 API 모음 즉, Saliency와 Person 같은 것과 결합합니다 각각 어떤 기능이 있는지 간단히 살펴보고 피사체 분리하기에 어떻게 활용할지 알아보죠 Saliency request는 Attention과 Objectness처럼 세밀하지 않은 영역 기반 분석에 많이 쓰입니다 생성된 Saliency 맵은 매우 해상도가 낮아서 세그멘테이션에 적합하지 않습니다 대신, 자동 이미지 자르기 같은 작업에 사용할 수 있죠 Person 세그멘테이션 API는 화면 내의 사람에 대한 세밀한 세그멘테이션 마스크를 만들 수 있죠 사람을 분리하는 데 중점을 둔다면 사용해 보세요 새로운 Person 인스턴스 세그멘테이션 API는 더 나아가 화면 내의 사람 각각에 대한 마스크를 제공합니다 더 알아보려면 Person 세그멘테이션 세션을 보세요 Person 세그멘테이션과는 다르게 새로 도입된 Subject lifting API는 물체를 식별하지 않습니다 전경 대상체라면 종류에 상관없이 분리될 수 있습니다 예를 들면, 이 이미지에서 차를 사람과 함께 선택한 것을 볼 수 있습니다 이제 관련된 핵심 개념을 살펴보죠 입력 이미지는 이걸로 하겠습니다 피사체 분리하기 요청은 이 이미지를 처리해서 같은 해상도의 부드러운 세그멘테이션 마스크를 만듭니다 이 마스크를 소스 이미지에 적용하면 마스크가 적용된 이미지가 나옵니다 뚜렷하게 분리된 각각의 대상체는 하나의 인스턴스로 취급되며 Vision은 또한 이런 인스턴스의 픽셀 정보도 제공합니다 인스턴스 마스크는 소스 이미지의 픽셀을 인스턴스 인덱스로 매핑하죠 인덱스 0은 배경을 가리키고 각각의 전경 인스턴스는 1부터 번호로 레이블이 붙죠 레이블이 번호로 붙긴 하지만 번호가 매겨지는 순서는 정해져 있지 않습니다 이런 인덱스는 소스 이미지의 전경 대상체를 구분하는 데 사용할 수 있습니다 상호작용이 되는 앱을 만든다면 이 인스턴스 마스크는 HitTest에도 유용합니다 잠시 후에 이런 작업을 어떻게 하는지 보여드리죠 API를 더 자세히 알아보겠습니다 피사체 분리하기는 Vision의 이미지 기반 요청의 익숙한 패턴을 따릅니다 먼저 전경 인스턴스 마스크 요청을 만듭니다 다음으로 ImageRequestHandler에 입력 이미지를 넣습니다 그런 다음 요청을 수행합니다 이때 Vision은 이미지를 분석하여 피사체를 파악합니다 Apple 하드웨어에 효율 면에서 최적화돼 있지만 리소스가 많이 필요한 작업입니다 UI를 방해하지 않기 위해 백그라운드 스레드로 돌리는 게 좋죠 이를 위해 많이 쓰는 방법이 이 과정을 DispatchQueue에서 비동시적으로 수행하는 겁니다 입력 이미지에서 하나 이상의 피사체가 감지되면 결과 어레이에는 단일 관찰값이 들어가 있겠죠 여기서부터 마스크와 분리된 이미지에 대한 관찰값을 요청할 수 있습니다 두 매개 변수를 더 자세히 살펴보죠 이 매개 변수들은 어떤 인스턴스를 분리할지 결과를 어떻게 자를지 제어합니다 인스턴스 매개 변수는 IndexSet입니다 최종 분리된 이미지나 마스크에서 어떤 대상체를 추출할지 제어하죠 예를 들어 이 이미지에는 두 개의 전경 인스턴스가 있습니다 배경 인스턴스는 없죠 감지된 전경 인스턴스를 모두 분리하는 건 아주 흔한 작업이므로 Vision은 편리한 allInstances 프로퍼티를 제공하죠 IndexSet엔 모든 전경 인스턴스의 인덱스가 들어 있습니다 이 이미지에는 인덱스 1과 2가 들어 있겠죠 배경 인스턴스 0은 없고요 인덱스의 부분 집합을 줄 수도 있습니다 여기서는 인스턴스 1을 여기서는 인스턴스 2를 줬습니다 또한 최종 마스킹된 이미지를 어떻게 자를지도 제어할 수 있죠 이 매개 변수는 false로 설정돼 있으면 출력 이미지 해상도를 입력 이미지와 일치시킵니다 이것은 분리된 대상체의 상대적 위치를 유지하고 싶을 때 유용합니다 이미지를 합성하는 작업이 이어질 경우에요 true로 설정하면 선택한 인스턴스에 딱 맞게 잘라냅니다 지금까지 예시에서는 완전히 마스킹된 출력 이미지로 작업했죠 하지만 어떤 작업에서는 마스킹된 효과를 적용할 때처럼 세그멘테이션 마스크만 가지고 작업하는 게 더 편리할 수 있어요 관찰값에 createScaledMask 메서드를 호출하면 이런 마스크가 나옵니다 매개 변수는 아까와 똑같이 동작합니다 출력 이미지는 단일 채널 부동 소수점 픽셀 버퍼로서 부드러운 세그멘테이션 마스크가 들어 있습니다 제가 방금 생성한 마스크는 Core Image와 아주 잘 맞습니다 Vision은 VisionKit처럼 출력물이 SDR(standard dynamic range)이죠 하지만 Core Image에서 마스킹을 수행하면 입력의 HDR(high dynamic range)을 유지할 수 있죠 이것에 관해 더 알아보려면 앱에 HDR을 추가하는 세션을 확인하세요 이 마스킹을 수행하는 방법은 CI의 blendWithMask 필터를 사용하는 겁니다 마스킹이 필요한 소스 이미지에서부터 시작하죠 이건 여러분이 Vision에 입력하는 이미지와 같은 겁니다 Vision의 createScaledMask에서 얻은 마스크입니다 마지막으로 새 배경 이미지인데요 이것은 피사체 밑에 합성되겠죠 비어 있는 이미지를 썼으니 배경이 투명할 겁니다 만약 새 배경 위에 결과물을 합성할 계획이라면 여기에 바로 넣어주면 됩니다 이제 다 설명해 드렸습니다 출력 결과는 HDR이 유지된 채로 마스킹 및 합성된 이미지겠죠 이런 것들을 써서 피사체 분리하기 시각 효과 앱을 만들어 보겠습니다 배경을 제거해서 그 아래에 있는 뷰들을 보여줄 수도 있죠 아니면 배경을 다른 걸로 바꾸거나요 또한 프리셋 효과를 적용할 수도 있죠 선택한 배경에 효과를 입힐 수도 있습니다 전경 인스턴스를 탭해서 선택적으로 분리할 수도 있어요 이 앱을 만들기 위해서 어떻게 접근할지 개요를 살펴보죠 이 앱의 핵심은 UI로 입력을 받아 최종 결과물을 내기까지 필요한 모든 작업을 수행하는 전체 과정에 있습니다 먼저 소스 이미지에서 피사체 분리하기를 수행합니다 선택 탭으로 개별 인스턴스를 선택하도록 합니다 결과를 내기 위한 마스크를 소스 이미지에 적용합니다 마지막으로 선택한 배경과 시각 효과를 적용하고 합성해서 최종 출력 이미지를 만듭니다 마지막 두 단계는 Core Image를 활용합니다 최상위 함수가 입력 이미지와 선택한 배경 이미지 및 효과를 비롯해 인스턴스 중 하나를 선택할 사용자의 탭 위치를 입력받죠 여기서 효과 유형은 그냥 간단히 프리셋 효과를 나열한 겁니다 출력은 최종 합성 이미지이며 UI에서 보이게 되죠 이 작업은 두 단계로 나눌 수 있습니다 먼저, 선택된 인스턴스에 대해 피사체 마스크를 생성합니다 다음 단계에서는 그 마스크를 써서 선택한 효과를 적용합니다 첫 단계부터 시작하죠 이번 단계의 입력은 소스 이미지와 선택 탭 위치입니다 여기 대부분의 코드는 이미 다 보셨던 것들인데 Vision의 request를 수행하고 반환값은 마스크입니다 재미있는 부분은 레이블 마스크를 이용하여 탭 위치를 인덱스 집합으로 매핑하는 이 라인입니다 좀 더 자세히 살펴보죠 탭이 빠지면 초깃값은 모든 인스턴스를 쓰는 걸로 합니다 탭 위치를 인스턴스 마스크의 픽셀로 매핑하고 싶습니다 여기에는 관련 정보가 두 개 있습니다 첫째, UI는 탭 위치를 보내기 전에 0과 1 사이의 값으로 표준화합니다 이건 좋은 겁니다, 세부 사항을 신경 쓰지 않아도 되니까요 디스플레이 해상도와 크기 조절 계수 같은 것들요 둘째, UI는 초기 설정된 UIKit 좌표계를 사용합니다 원점이 왼쪽 맨 위죠 이것을 픽셀 버퍼의 이미지 공간 좌표계와 맞춰야죠 이 변환을 수행하기 위해 기존의 Vision helper 함수를 사용합니다 탭한 인스턴스 레이블을 찾는 데 필요한 정보는 다 있습니다 이것은 픽셀 버퍼 데이터에 직접 액세스하는 것을 포함합니다 나중에 어떻게 하는지 알려 드리겠습니다 레이블을 찾으면 0이 아닌지 확인합니다 레이블이 0이란 건 사용자가 배경 픽셀을 탭했다는 뜻이죠 이 경우에는 모든 인스턴스를 선택하는 것으로 하겠습니다 그렇지 않다면 선택된 레이블에 해당하는 단독 집합을 반환하겠죠 이 코드는 인스턴스 레이블 찾기가 어떻게 수행되는지 보여줍니다 데이터에 액세스하기 전에 픽셀 버퍼를 먼저 고정해야 합니다 읽기 전용 액세스면 우리 목적에는 충분하죠 픽셀 버퍼는 크기를 맞추기 위해 패딩될 수 있으므로 픽셀에 대한 바이트 오프셋을 계산하는 가장 확고한 방법은 픽셀의 bytesPerRow 값을 이용하는 것입니다 instanceMask가 단일 채널 UInt8 버퍼이기 때문에 크기 조절은 신경 쓸 필요가 없습니다 인스턴스 마스크를 읽어 들여서 버퍼를 해제할 수 있죠 그 결과 선택된 인스턴스만 있는 마스크를 얻게 됩니다 이제 효과를 적용해 보죠 여기서 첫 번째 단계는 배경에 선택한 효과를 적용하는 겁니다 그게 끝나면 Core Image를 써서 마스킹된 피사체를 합성합니다 효과가 적용된 배경 위에다가요 처음 몇 가지 효과는 단순하고 직접적으로 기존의 Core Image 필터들을 적용한 거죠 예를 들어 피사체 강조하기는 배경을 어둡게 하는 노출 조정 필터를 사용했습니다 보케 효과는 약간 더 복잡합니다 배경을 흐릿하게 하는 것 외에 선택된 피사체를 후광으로 강조해야 합니다 흐릿하게 하기 전에 피사체에 맞춰 하얗게 잘라내면 됩니다 이를 위한 가장 빠른 방법은 현재 함수를 재사용하고 피사체 자리에 흰색 무지를 채워 넣으면 되죠 이것을 합성의 기초 레이어로 삼겠습니다 마지막으로 앞서 얘기했던 Core Image 블렌딩을 추가합니다 분리된 피사체를 새롭게 변형된 배경 위에 합성하죠 효과 파이프라인의 마지막 부분이 들어가면서 앱이 완성됐습니다 새로운 피사체 분리하기 API의 가능성을 확인하셨길 바랍니다 정리하면 Visionkit은 가장 빠르게 여러분의 앱에 피사체 분리하기를 넣을 수 있는 방법입니다 좀 더 고급 응용을 위해서는 Vision API를 씁니다 마지막으로 Core Image를 사용하면 HDR이 적용된 이미지에서 피사체 분리하기를 처리할 수 있죠 이 영상을 재밌게 보셨길 바랍니다 여러분이 어떤 것을 만들어 낼지 무척 기대됩니다 ♪ ♪
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.