yuna dev history

[Android] ImageReader에서 YUV로 받은 Image 객체 회전rotate하기 본문

프로그래밍언어/안드로이드

[Android] ImageReader에서 YUV로 받은 Image 객체 회전rotate하기

모과쟁이 2023. 1. 25. 10:41
  • 글 작성 이유: 구글에서 코드 찾다가 도저히 못 찾아서 그냥 바이트 단위로 쪼개서 rotate하도록 바꾸는 코드를 그냥 썼기 때문에 다른 사람은 고생하지 않았으면 해서.
  • 전면 카메라 front camera에서 YUV420_888 이미지(android.media.Image 객체)를 받아온다. ImageReader에서 받아온 image 객체를 byte 버퍼로 바꾸고, 버퍼로 받아온 YUV를 반시계 방향으로 90도 회전시킨 형태의 바이트 버퍼로 변환한다.
  • 필요했던 이유: 카메라를 회전해도 폰의 UI는 업데이트가 될지 몰라도 내부에서 실제로 받아오는 이미지의 버퍼 순서?는 변하지 않는다. 근데 내부 함수에서 회전한 버퍼?를 원했다.
  • 주의해야 할 점 몇 가지
  1. YUV420_888 포맷을 유지한 채 android.media.image -> byte buffer로 바꾸는 과정
    • YUV420_888 포맷은 Y가 Width*Height만큼 나오고 그 다음에 U와 V가 번갈아가며(순서는 UV순) 나오되 Width * (Height/2) 만큼만 나온다.
    • Y 4개에 U, V가 각각 하나씩 매칭되는데, 예를 들어
      Y1 Y2 Y3 Y4
      Y5 Y6 Y7 Y8
      U1 V1 U2 V2
      라고 하면 Y1, Y2, Y5, Y6이 U1, V1과 매칭되는 식이다.
  2. Front Camera관련
    • 프론트 카메라에서 X, Y Coordinate가 정해져있고, 이게 그냥 생각한 거랑 다르다
    • (0, 0)이 오른쪽 맨 아래에 위치한다.
    • 폰이 portrait으로 있다고 할 때, X 증가 방향은 세로, Y 증가 방향은 가로다
    • 따라서 안에 코드를 찍어보면 폰이 portrait으로 있다고 할 때, Image Width가 폰의 세로 길이, image height 가 폰의 가로길이가 되며, image width > image hegiht인 상태가 된다.
    • http://zhengrui.github.io/android-coordinates.html
    • 위 사이트 그림을 참고하면 이해하기 쉽다
  3. android.media.Image 객체를 YUV420_888포맷을 유지한채 byte buffer로 바꾸는 코드는 여기저기 많이 있으니 여기서는 생략
  • 아래 코드가 하는 일

    • android.media.Image객체는 YUV420_888 형태를 유지한 채로 byte buffer로 변환되어 있다고 할 때, 받아온 byte buffer를 반시계 방향 90도 돌려서 portrait의 byte buffer와 같은 순서인 (오른쪽 맨 아래에서부터 byte가 쌓이는 순서를 지켜가며) buffer가 되도록 rotate하기

      
        public byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight)
      {
        byte [] yuv = new byte[imageWidth*imageHeight*3/2];
        // Rotate the Y luma
        int i = 0;
        for (int x=0; x<imageWidth; x++) {
            for (int y=imageHeight-1; y>=0; y--) {
                yuv[i++] = data[imageWidth*y+x];
            }
        }
      
        // Rotate the U and V color components
        for (int x=0; x<imageWidth; x+=2) {
            for (int y=imageHeight/2-1; y>=0; y--) {
            // copy U
                yuv[i++] = data[imageWidth*imageHeight+imageWidth*y+x];
            // copy V
                yuv[i++] = data[imageWidth*imageHeight+imageWidth*y+x+1];
            }
        }
        return yuv;
      }
      
    • 비슷하게 코드를 짜면 180, 170도 같은 형태의 코드를 만들 수 있다.

    • 무식하게 짰기 때문에 더 나은 코드가 있을 수 있으니 주의

'프로그래밍언어 > 안드로이드' 카테고리의 다른 글

[Android] Context란?  (0) 2019.06.26