본문 바로가기

OnePIC (Android App)/사진 편집 기능

[얼굴 변경 :Face Blending] 두 사진에서 동일 얼굴 찾기

반응형

 
동시에 찍힌(연사된) n장의 사진이 주어질 때, 동일 얼굴을 찾아서 바꾸는 기능을 구현하고자 한다.
해당 기능을 본 프로젝트에서는 Face Blending이라고 칭한다.
 
본 포스팅에서는 두 사진에서 동일 얼굴 찾는 방법을 작성하고자 한다.
참고로 각 사진에 얼굴에 관한 정보는 MLKit FaceDetection를 사용한다.
 

[얼굴 감지] MLKit를 활용한 얼굴 감지

OnePIC을 만들면서 필자가 겪었던 어려움들과 깨달음들에 대해서 포스팅 해보려고 한다. 이번 포스팅은 얼굴 감지를 하기 위해 시도한 여러가지 기술(API)들에 대해서 설명하고 결론적으로 선택한

kyumq.tistory.com


 

동일 얼굴 찾는 방법 (예상)

 
1) MLKit FaceDetection을 사용해서 얻어지는 Face ID를 비교해 동일 ID일 경우 동일 얼굴로 판단
2) MLKit FaceDetection을 사용해서 얻어지는 얼굴 위치(좌표값)를 비교해 비슷한 위치일 경우 동일 얼굴로 판단
 
 

 Face ID 비교 (불가능)

 
Face Detector 구성할 때, enableTracking 을 true로 설정한다.

얼굴에 ID를 할당할지 여부이며, 여러 이미지에서 얼굴을 추적하는 데 사용할 수 있습니다.
윤곽 감지가 사용 설정된 경우 얼굴이 하나만 인식되므로 얼굴 추적에서 유용한 결과를 얻지 못합니다. 따라서 감지 속도를 개선하려면 윤곽 인식과 얼굴 추적은 모두 사용 설정하지 마세요.

 
이 때 얻어지는 ID는 여러 이미지에서 얼굴을 추척하는데 사용된다.
 
이 설명글을 처음에는 다음과 같이 판단했다.
: 판독기가 사진 분석을 기억해, 여러사진을 판단할 때 동일 얼굴도 판단해주는줄 알았다. (여러 사진에서 동일 얼굴 판단 기능)
 
하지만 이와 다르게 이 기능은 실시간 얼굴 감지할 때, 얼굴을 추척하는 기능이었다.

추가설명
: 연속 프레임을 처리할 때 각 얼굴에 대해 일관된 ID를 유지하는 얼굴 추적을 활성화합니다. 
  연속되지 않은 일련의 스틸 이미지를 처리하려면 추적을 비활성화해야 합니다.

 

얼굴 좌표 값 비교 (가능)

 
2가지 사진을 비교하는 걸로 테스트한다.
그래서 1번 사진 중 원하는 얼굴을 클릭했을 때, 2번 사진에 있는 얼굴들 중 클릭좌표와 비슷한 위치에 있는 얼굴을 동일 얼굴로 판단한다.
 
 
연사된 사진에서 동일 얼굴을 찾는 것이므로, 해당 값을 비교해서 구하는 것도 가능하다고 판단한다.
 


 

Face Detection 실행 시 얻어지는 얼굴 좌표 값 설명

 
 
Face Detection 실행하면 얼굴 좌표 값은 Rect로 반환된다.

Rect : 네모 상자의 top, left, bottom, right 좌표 값

 

 


 

얼굴 좌표 값 비교 하기

 
작성을 쉽게 하기 위해 변경을 원하는 1번 사진을 original이라 칭하고, 변경하고자 하는 얼굴이 포함된 2번 사진을 change라 칭한다.
 
 

1. 클릭 좌표 구하기 (x, y)

 
original을 화면에 띄운 다음 변경을 원하는 얼굴을 클릭하게 한다. 
사진이 띄어진 ImageView에 setOnTouchListener를 통해 클릭 좌표를 구할 수 있다.
 
하지만 ImageView와 실제 이미지와는 크기가 달라, TouchEvent로 얻어진 point를 이미지 크기에 맞춘 터치 point로 변환해야한다.
변환하는 코드는 다음과 같다.

                    // click 좌표를 bitmap에 해당하는 좌표로 변환
                    val touchPoint = imageToolModule.getBitmapClickPoint(
                        PointF(event.x, event.y),
                        binding.imageView
                    )

 

이벤트가 발생하면 클릭 좌표를 얻은 후 changeFace 함수를 호출한다. 
changeFace ( ... ) : 얼굴 변경 테스트를 위한 함수, 두 사진을 비교해 변경을 원하는 얼굴 위치를 전달하면 얼굴을 바꾼다.

 
 

2. original에서 (x, y)가 포함되는 얼굴 찾기

 
original 사진을 MLKit의 FaceDetection 실행 후 결과 얻기
결과로 얼굴들 정보가 얻어진다 : List<Face>
List로 얻어지는 Face에서 얼굴 위치 정보인 Rect를 확인한다.
 

checkPointInRect 함수로 알아내기 

Rect로 얻어지는 위치 좌표에서 left, right와 x 비교 : left ≤ x  right
Rect로 얻어지는 위치 좌표에서 top, bottom와 y 비교 : top y  bottom
 

    /**
     * checkPointInRect(point: Point, rect: Rect):
     *          point 가 rect 안에 존재하는 지를 알아낸다.
     *          존재하면 true 존재하지 않으면 false
     */
    fun checkPointInRect(point: Point, rect: Rect): Boolean {
        // 포인트가 boundingBox 안에 존재할 경우에만 실행
        // -> boundinBox.left <= x <= boundingBox.right && boundingBox.top <= y <= boundingBox.bottom
        return point.x >= rect.left && point.x <= rect.right &&
                point.y >= rect.top && point.y <= rect.bottom
    }

 
 

3. 알아낸 얼굴의 중심점(newX, newY) 구하기 

 
얼굴의 중심점 구하는 방법은 해당 Face에서 중심점은 다음 수식으로 알아낼 수 있습니다.
중심점(left + right / 2 , top + bottom / 2)
 

4. change에서 중심점(newX, newY)이 포함되는 얼굴 찾기

 

[2. original에서 (x, y)가 포함되는 얼굴 찾기]와 동일한 로직으로 이뤄진다.

 
 
change 사진을 MLKit의 FaceDetection 실행 후 결과 얻기
결과로 얼굴들 정보가 얻어진다 : List<Face>
List로 얻어지는 Face에서 얼굴 위치 정보인 Rect를 확인한다.
 

checkPointInRect 함수로 알아내기 

Rect로 얻어지는 위치 좌표에서 left, right와 newX 비교 : left ≤ newX ≤ right
Rect로 얻어지는 위치 좌표에서 top, bottom와 newY 비교 : top ≤ newY ≤ bottom
 
 

반응형