결론은 'getBitmap 메서드를 되도록이면 사용하지 말자' 입니다.
이번에 랩실 프로젝트에서 제가 맡은 부분은 모델이 주는 bounding box를 스크린에 출력하는 것이었습니다.
모델이 얼마나 빠르게 결과를 주던, 입력과 출력 사이에 계산하는 시간이 길면 길수록
출력되는 bounding box와 사용자가 보고있는 화면의 시간차는 계속해서 늘어납니다.
미리보기 화면 -> 화면에 대한 비트맵 이미지 -> 모델 -> bounding box 그리기
위와 같은 흐름을 구성했는데, 핵심은 미리보기 화면(previewView)에서 ImageAnalyzer를 통해 얻는 화면에 대한 비트맵 이미지는 계속해서 모델이 가져가도록 하고, 나중에 출력으로 나온 bounding box와 그때 사용자가 보고있었던 화면을 시간차 없이 보여주기 위해 previewView.getBitmap() 을 사용하여 가져오도록 했습니다.
이는 정확한 bounding box결과를 표시하는 문제를 해결할 수 있었으나, 시간이 흐를수록 시간차가 커지고 하나의 프레임을 처리하는데 들어가는 시간 비용이 약 100ms(10fps)정도 나왔습니다.
텐서플로우 라이트에서 제공하는 객체 탐지 코드에 들어있는 모델들도 순수하게 cpu만 사용하면 100ms를 넘는 모델들도 많았기 때문에 처음에는 별 상관 안했지만, 점점 현실과 딜레이가 생기는 제 구현을 보고있자니 속이 탔습니다.
그쯤 모델을 내장하는 방식이 아니라 서버와 통신하는 방식으로 바꿨는데, 서버에서 결과를 주는 속도와 휴대전화에서 처리하는 속도가 이상할정도로 차이가 났습니다.
ImageView에 setImageBitmap 메서드로 결과 이미지를 계속 출력하고 있었기 때문에 이게 느린가 싶어 여러가지 시도를 해봤으나 아무 의미가 없었습니다.
2주정도 헤메고 다시 텐서플로우 라이트 예시 코드를 살펴보니 getBitmap 메서드를 부르는 부분이 하나도 없어 앱에도 똑같이 적용해보니 150ms 정도 나오던 계산속도가 4~5ms로 줄어들었습니다.
Bounding box 출력이 딜레이를 가지는 것을 감안하더라도 30ms 안쪽으로 처리되면 시간차가 그렇게 크게 체감되지 않았으므로 이것이 해법이었습니다.
할 수 없이 반복적으로 화면 이미지를 받아서 출력해야하는 경우라면, 화질을 포기하더라도 ImageAnalyzer를 사용하는 것이 최선이라고 생각합니다.
getBitmap 메서드가 성능이 좋지 않은 이유는 정확한 이해가 없어 설명이 충분하지 않으나, 반복적으로 (화면의 높이 * 너비 * 3) * 1 byte 만큼의 크기를 가진 데이터를 뽑는데 빠른 속도를 낼 수 없다는 것으로 이해하려 합니다.
'안드로이드' 카테고리의 다른 글
[안드로이드] PreviewView가 다른 View를 overlap하는 경우 (0) | 2023.02.11 |
---|---|
[안드로이드] 앱 강제 종료 (0) | 2023.02.10 |
[안드로이드] ViewBinding 사용해보기 (0) | 2022.05.24 |
[안드로이드] RecyclerView 사용 및 클릭 이벤트 넣어보기 (0) | 2022.05.14 |
[안드로이드] 뒤로 가기 두 번 누르면 종료되게 만들기 (0) | 2022.05.11 |