Tistory View
그리 어려운 개념은 아니지만, image의 stride는 늘 나를 괴롭힌다.
image를 다룰 때마다 신경을 안 쓸 수가 없는 부분이며, 정확히 명시되어있지 않는 상황에서는 일일이 테스트를 거쳐 파악을 해야할 경우도 다반사다.
stride는 이미지의 한 줄(row)의 크기를 나타내는 것으로 이미지의 width와는 다른 개념이다.
이미지를 메모리든 파일이든 저장된 형태를 결정짓는 부분이다.
한 픽셀이 RGB 3바이트로 구성된 이미지를 예를 들어 보자. 이미지의 크기가 3x3으로 가정하고 다음의 구조를 보자.
RGB RGB RGB PPP
RGB RGB RGB PPP
RGB RGB RGB PPP
P : padding
위의 이미지는 width값은 3[RGB]*3[byte per pixel]이지만,
stride값은 PPP부분의 3byte를 더한 12bytse가 된다.
전체이미지 크기는 12 * 3 = 36bytes가 된다.
Padding을 두는 이유야 당연히 CPU가 메모리에 접근하는 속도때문인데, 실제 4,8,16-bytes등에 잘 맞춰진 이미지는 그렇지 않은 것보다 빠르게 처리된다.
(실제 테스트를 해보면 상당히 빨라지는 것을 알 수 있다.)
위 예제의 이미지 4-bytes로 align되어있다고 표현하는 데, 한 줄(row)이 [4bytes단위에서 끝난다]는 뜻이다.
12 % 4 => 0 이 된다.
다음의 그림을 보자, 동일한 RGB의 3x3 의 이미지이다. 위의 예제에서 padding이 없을 뿐이다.
RGB RGB RGB
RGB RGB RGB
RGB RGB RGB
위 이미지의 width값은 9bytes 이고 stride 또한 9bytes이다.
이미지의 전체 크기는 9bytes * 3 = 27bytes이다.
뭐 어려운 부분은 아니지만, stride값은 저장하는 사람맘이라 다음의 이미지 또한 3x3의 이미지이다.
RGB RGB RGB PPP PPP P
RGB RGB RGB PPP PPP P
RGB RGB RGB PPP PPP P
width = 3bytesx3pixel
stride = 16bytes
이미지 전체 byte크기 = width * stride = 48bytes
위의 이미지는 솔직히 상당히 메모리 낭비가 심한 방식으로 보이지만, 이미지의 크기가 보통 적지 않기 때문에 실제 낭비하는 부분은 그리 많지 않을 수 있다.
예를 좀 심하게 들어서 그렇지, 실제로 16bytes-align으로 처리하는 경우도 많다(SIMD처리용으로 주로 쓰인다. 물론 SIMD에서는 RGBA를 쓰겠지만..)
따라서 이미지를 다룰 경우 단순히 width, height만으로 계산하면, 그림이 물결치거나 한쪽으로 밀리거나 하는 문제가 발생한다.
보통 1,2,4,8,16,32식으로 align을 시키는 데, 이 걸위해 주로 다음과 같은 계산식을 쓴다.
4byte로 align할 경우
stride = w + ( w % 4 != 0 ? 4 - w % 4 : 0 );
8byte로 align할 경우
stride = w + ( w % 8 == 0 ? 8 - w % 8 : 0 );
C-compiler가 이 정도의 코드는 알아서 최적화를 하지만, 좀 쓸데없이 멋있게 만들어야 할 경우 다음의 코드를 쓴다.
(기계어로 컴파일하는 언어가 아닐 경우 다음의 코드를 쓰면 좀 빨라진다.)
4byte로 align할 경우
stride = w + ( (w & 3 ) ? : 4 - ( w & 3 ) : 0 );
8byte로 align할 경우
stride = w + ( ( w & 7 ) ? 8 - ( w & 7 ) : 0 );
이미지를 다를 때는 다음의 값을 미리 계산해 두고 사용하면 편하다. 또한 오류를 줄일 때도 도움이 된다.
bytePerPixel |
픽셀당 byte수 |
width |
이미지 폭 |
height |
이미지 높이 |
stride |
width * bytePerPixel + padding |
이미지의 전체 크기 |
stride * height |
|
|
uint32_t bytePerPixel = 3;
uint32_t width = 640;
uint32_t height = 480;
uint32_t padding = width % 4 ? 4 - width % 4 : 0;
uint32_t stride = width * bytePerPixel + padding;
uint32_t imageSize = stride * height;
필자의 경우 웬만하면 RGBA식으로 4byte로 끝날수 밖에 없는 이미지로 사용하지만(무조건4byte-align될 수 밖에 없다.), 다른 소스에서 넘어오는 것을 처리하려면, 어쩔 수 없이, 다시 풀어야 해서 이렇게 복붙용으로 만들어 둔다.
주의 사항
stride는 늘 width보다 같거나 크다.
stride값을 byte단위로 주로쓰지만 pixel단위로 표현할 경우도 적지 않다.
stride값은 저장하는 사람이 정하기 나름이므로 이미지를 다루는 모든 상황에서 늘 고려해야 한다.
다른 표현으로 pitch라는 표현도 있다. (같은 표현이다.)
이 포스팅만으로는 별로 도움이 안되므로, 다음에 언젠가 다음의 내용으로 포스팅을 하겠다.
OpenGLES에서 stride적용하기
안드로이드 YV12에서의 stride
혹시나 해서 이 글을 보고 공부하는 친구가 있을 지 몰라 한가지 더 이야기 하면...
4byte-aligned의 또다른 의미는 이미지의 시작하는 첫 픽셀 부분[메모리 시작번지]도 4로 나누어 져야한다.
실제 메모리는 4byte로 처리를 많이 하는데, 16byte-aligned일 경우는 좀 더 다른 함수를 써야 한다.
'Android Develop > image' 카테고리의 다른 글
안드로이드 ImageView의 ScaleType (0) | 2019.12.04 |
---|---|
Android YV12, stride and RGB conversion (0) | 2019.08.06 |
안드로이드 YV12, stride와 RGB 변환 (4) | 2019.08.06 |
Android NDK Access memory of Bitmap directly (5) | 2019.08.05 |
Android NDK Bitmap 메모리에 접근하기 (2) | 2019.08.05 |
- Total
- Today
- Yesterday
- OpenGL ES
- 공유 컨텍스트
- 재태크
- 적금
- 전기세
- TTS
- 안드로이드
- choreographer
- 애드핏
- Android
- 에어컨
- texture
- gpgpu
- OpenGLes
- 컴퓨트쉐이더
- 티스토리
- 사용료
- 아끼는 법
- ComputeShader
- 블로그
- 금리
- 재테크
- 컴퓨트셰이더
- 예금
- 에어콘
- 애드센스
- 텍스처
- 경제보복
- 전기료
- 전기요금
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |