색상 형식
색상은 디스플레이의 픽셀을 통해 보이는 것을 말합니다. 이러한 색상은 프레임버퍼에 저장된 값에서 비롯됩니다. 일반적으로 그래픽 시스템은 표현, 사용 및 표시할 수 있는 색상의 크기가 제한되어 있습니다. 이는 TouchGFX와 TouchGFX 애플리케이션에서도 마찬가지입니다.
애플리케이션에서 가능한 픽셀 색상 수에 따라 애플리케이션의 많은 부분이 영향을 받는데, 이를테면 디스플레이에 나타나는 시각적인 모습부터 프레임버퍼의 메모리 사용량, 그리고 전반적인 성능이 달라지게 됩니다. 이 섹션에서는 TouchGFX에 사용되는 색상에 대해 자세히 살펴보고 TouchGFX에서 사용할 수 있는 색상 형식을 비롯한 장단점을 집중적으로 알아보겠습니다.
색상
TouchGFX에서는 RGB 색상이라고 알려진 빨간색, 녹색, 파란색 성분이 사용됩니다. 각 색상 성분은 0부터 255까지 다양합니다. 0은 해당 성분이 전혀 없는 것을, 그리고 255는 해당 성분이 가득한 것을 말합니다.
RGB에서 완전한 검은색은 (0,0,0), 완전한 흰색은 (255,255,255)으로 표시됩니다. 밝은 녹색은 (0,255,0), 중간 밝기의 빨간색은 (128,0,0), 어두운 보라색은 (64,0,64)입니다.
그레이스케일
그레이스케일(grayscale) 애플리케이션에서는 검은색에서 흰색까지 모든 색상이 회색입니다. 따라서 RGB 값이 아니라 회색 강도로 표현됩니다. 따라서 그레이스케일 색상은 R과 G, B가 동일한 RGB 색상이라고 볼 수도 있습니다.
불투명도
일부 환경에서는 색상에 불투명도를 지정하는 성분을 추가하기도 합니다. 불투명도 역시 나머지 색상 성분과 마찬가지로 0부터 255까지 다양합니다. 불투명도가 지정된 색상을 RGBA 색상이라고 합니다. 여기서 A는 알파값으로, 불투명도에 사용되는 명칭입니다.
여기서 완전히 불투명한 검은색은 (0,0,0,255)이고, 다수 투명한 빨간색은 (255,0,0,128)입니다.
색상이 완전히 불투명하지 않을 때는 기존 색상과 함께 혼합해야 합니다. 이러한 색상 혼합을 알파 블렌딩이라고 합니다.
색 심도
색 심도(color depth)란 프레임버퍼에 저장된 색상들을 하나씩 나타낼 때 사용되는 비트 수를 말합니다. 이러한 수치는 픽셀당 비트로 나타내며, 줄여서 bpp라고 표기합니다.
사용되는 비트 수가 많을수록 더 많은 색상을 표현할 수 있습니다.
많이 사용되는 색 심도는 24bpp입니다. 각 비트를 표시할 수도 있고, 표시하지 않을 수도 있기 때문에 표현 가능한 색상 수는 224, 즉 16777216개입니다.
또한 비교적 적게 사용되는 색 심도는 1bpp입니다. 이 색 심도는 흑백 애플리케이션에 적용됩니다. 이 말은 표현 가능한 색상이 21, 즉 2개에 불과하다는 것을 의미합니다.
TouchGFX에서 기본적으로 지원되는 색 심도는 다음과 같습니다.
- 32bpp - 색상 16777216개와 해당하는 불투명도 값
- 24bpp - 색상 16777216개
- 16bpp - 색상 65536개
- 6bpp - 색상 32개
- 4bpp - 그레이스케일 색상 16개
- 2bpp - 그레이스케일 색상 4개
- 1bpp - 그레이스케일 색상 2개
색상 성분 범위에 대해 알아야 할 것이 있습니다. 색 심도가 24bpp 미만일 경우 빨간색, 녹색 및 파란색 성분의 각 범위는 0~255가 아닙니다. 예를 들어 빨간색의 심도가 16bpp라고 가정할 경우 빨간색 성분의 범위는 0~31입니다. 24bpp에서 255인 것처럼 16bpp에서 가장 진한 빨간 색상을 표현하려면 값은 31이 됩니다. 이렇게 생각할 수 있는 이유는 색 심도가 16bpp인 색상들은 24bpp에서 가능한 색상의 하위 집합만 표현할 수 있기 때문입니다.
형식
지금까지 색상을 표현하는 데 필요한 비트의 크기에 대해 살펴보았으니, 이제 비트의 내용에 대해 더 자세히 알아보겠습니다. 색상에는 빨간색이든, 녹색이든, 파란색이든 각 성분을 나타내는 비트가 있습니다.
픽셀 색상 형식
애플리케이션의 색 심도에 따라서 몇 가지 사용할 수 있는 색상 형식이 있습니다.
RGB888
TouchGFX에서 색 심도가 24bpp인 색상의 형식은 RGB888입니다. 이 말은 빨간색, 녹색 및 파란색 성분마다 8비트가 사용된다는 것을 의미합니다.
이러한 색상, 예를 들어 밝은 보라색 rgb(255,0,255)를 코드로 표현하려면 아래와 같이 각 성분을 색상 값으로 조합해야 합니다.
uint32_t brightPurpleRGB888 = 255 << 16 | 0 << 8 | 255 << 0;
RGB565
16bpp 색상에서 TouchGFX가 사용하는 색상 형식은 RGB565입니다. 즉, 빨간색은 5비트, 녹색은 6비트, 파란색은 5비트입니다. 빨간색이 5비트이면 완전히 밝을 때 31이므로 밝은 빨간색의 코드는 아래와 같습니다.
uint16_t brightPurpleRGB565 = 31 << 11 | 0 << 5 | 0 << 0;
RGBx2222, xRGB2222, BGRx2222, xBGR2222
6bpp 색상에서는 TouchGFX가 4가지 다른 형식, 즉 RGBx2222, xRGB2222, BGRx2222, xBGR222를 지원합니다. 이러한 형식에 x가 있는 이유는 6비트 색상이 바이트로 저장되기 때문입니다. 색상은 2비트씩 채워져 1바이트를 형성합니다. 또한 RGB와 BGR을 모두 지원하는 이유는 일부 디스플레이에 BGR이 필요하더라도 이러한 디스플레이에 전송하기 전에 픽셀을 변환하지 않기 위해서입니다. 밝은 노란색을 RGBx2222로 표현하는 코드는 아래와 같습니다.
uint8_t brightYellowRGBx2222 = 3 << 6 | 3 << 4 | 0 << 2;
GRAY4, GRAY2, BW
TouchGFX는 그레이스케일 색상 심도에 따라 해당하는 한 가지 색상 형식을 지원합니다. 예를 들어 4bpp일 때 색상 형식은 GRAY4이고, 2bpp일 때는 GRAY2이며, 1bpp일 때는 흑백을 의미하는 BW입니다. 4bpp일 때 완전히 흰색은 아래와 같습니다.
uint8_t whiteGRAY4 = 15;
TouchGFX에는 색상 형식에 따라 정확한 색상 표현을 반환하는 헬퍼 함수가 포함되어 있습니다.
#include <touchgfx/Color.hpp>
...
aColor = Color::getColorFromRGB(255,0,128);
이미지 형식
이미지는 대부분의 UI 애플리케이션에서 매우 중요한 역할을 하며, 여러 가지 색상으로 채워집니다. TouchGFX에서는 이미지가 메모리에 저장되며, 특정 형식의 색상으로 채워집니다. 대부분의 경우 이미지는 지원되는 픽셀 색상 형식 중 하나를 사용하지만 그 밖에 다른 이미지 형식도 사용할 수 있습니다. 특정 이미지 색상 형식의 이미지에서 픽셀은 해당하는 픽셀 형식으로 변환된 후 그리기 작업을 하게 됩니다.
이미지 색상 형식 | 표현 |
---|---|
ARGB8888 | 32비트, 성분당 8비트 |
L8_ARGB8888 | 8비트 인덱스 형식, ARGB8888 팔레트 |
RGB888 | 24비트, 성분당 8비트 |
L8_RGB888 | 8비트 인덱스 형식, RGB888 팔레트 |
RGB666 | 24비트, 성분당 6비트 |
RGB565 | 16비트, 빨간색 5비트, 녹색 6비트, 파란색 5비트 |
L8_RGB565 | 8비트 인덱스 형식, RGB565 팔레트 |
ARGB2222 | 8비트, 성분당 2비트 |
ABGR2222 | 8비트, 성분당 2비트 |
RGBA2222 | 8비트, 성분당 2비트 |
BGRA2222 | 8비트, 성분당 2비트 |
GRAY4 | 4비트 그레이스케일 |
GRAY2 | 2비트 그레이스케일 |
BW | 1비트 그레이스케일 |
BW_RLE | 1비트 그레이스케일 런 길이 인코딩(RLE) |
위의 이미지 형식 중에서 L8 형식은 해당하는 이미지를 색상 룩업 테이블(CLUT)과 테이블에 대한 인덱스로 표현합니다. L8 이미지에서 가능한 최대 색상 수는 28개, 즉 256개입니다. L8 형식은 다른 형식에 비해 차지하는 공간이 비교적 적습니다. 예를 들어 100x100 이미지에 200가지 색상이 있다고 가정할 경우 ARGB8888 형식으로 저장하면 100x100x32비트, 즉 40000바이트의 공간을 차지하지만 L8_ARGB8888 형식으로 저장하면 100x100x8비트 + 200x32비트, 즉 10800바이트의 공간을 차지하게 됩니다.
BW_RLE 형식은 단일 픽셀 색상이 아닌 연속된 흑백 이미지로 색상을 저장합니다. 이렇게 하면 대부분 경우 공간을 더욱 효율적으로 사용할 수 있습니다.
나머지 형식들은 위의 픽셀 색상 형식과 동일합니다.
텍스트 형식
텍스트는, 더욱 엄밀히 얘기하면 글리프(glyph) 역시 특정 색상 형식으로 메모리에 저장됩니다. TouchGFX에서 사용할 수 있는 텍스트 색상 형식은 다음과 같습니다.
텍스트 색상 형식 | 표현 |
---|---|
A8 | 8비트, 불투명도 전용 |
A4 | 4비트, 불투명도 전용 |
A2 | 2비트, 불투명도 전용 |
A1 | 1비트, 불투명도 전용 |
글리프 형식은 작은 이미지와 비슷합니다. 여기에서는 색상 항목마다 각 픽셀의 불투명도가 저장됩니다. 이렇게 하면 실제 색상, 즉 빨간색, 녹색 및 파란색 성분을 나중에 적용할 수 있으며, 이를테면 저장된 글리프 ‘A’를 파란색 버전과 빨간색 버전으로 그리는 것도 가능합니다.
각 글리프마다 사용되는 비트 수가 많을수록 텍스트가 더욱 자연스럽고 선명하게 표시됩니다.
시각적 품질
임베디드 그래픽을 처리할 때는 시각적 품질을 최대한 높이고 싶은 마음이 당연하겠지만 메모리 사용량도 함께 고려해야 합니다.
따라서 색상이 더 풍부한 RGB888보다는 RGB565 색상 형식을 사용하는 것이 더 바람직합니다. 일반적으로 메모리 요건을 감안하여 시각적 품질을 최대한 높일 수 있는 색상 형식을 따르는 것이 좋습니다.
디더링
TouchGFX는 이미지를 여러 가지 색상 형식으로 표현할 때 시각적 품질을 높여주는 디더링이라고 하는 기법을 사용합니다.
디더링(Dithering)은 이미지의 색상을 실제보다 더 많아 보이게 만드는 기법으로 잘 알려져 있습니다. 이 기법은 이미지의 색상에 약간의 노이즈를 추가하는 방식입니다.
예를 들어 각 색상 성분에서 낮은 비트를 잘라내지 않고 RGB888 이미지를 RGB565 이미지로 변환한다고 가정할 경우 변환 프로세스에서 노이즈가 각 색상에 추가됩니다. 그러면 변환된 이미지의 색상이 더욱 풍부해져 원본인 RGB888과 비슷하게 보입니다.
아래 RGB888 원본 이미지와 변환된 이미지들을 가지고 이미지를 보면서 설명하겠습니다. 변환된 이미지의 형식은 각각 디더링을 적용한/적용하지 않은 RGB565와 xRGB2222, 그리고 GRAY4입니다.
위에서도 알 수 있듯이 디더링은 인지할 수 있는 이미지의 품질을 크게 개선하는 효과가 있습니다. 디더링이 적용된 RGB565 이미지와 그렇지 않은 이미지를 자세히 보면 디더링이 적용된 버전은 원본과 거의 차이가 없지만 디더링이 적용되지 않은 버전은 일부 영역에서 색상 밴딩 현상이 확연하게 보입니다. 이로써 대부분 경우 16비트 색상으로도 그래픽을 충분히 선명하게 표현할 수 있다는 것을 잘 보여주고 있습니다.
그래픽 애셋(asset)에 커다란 그래디언트(두 영역간 색의 변화도)가 있다면 디더링이 적용된 이미지에서도 색상 밴딩 현상이 나타날 수 있습니다. 여기 두 가지 예가 있습니다. 하나는 RGB888(64,190,222)에서 검은색에 이르는 파란색 그래디언트와 디더링을 적용하고/적용하지 않고 변환된 RGB565 이미지입니다.
또 하나는 (255,0,0)에서 검은색에 이르는 빨간색 그래디언트입니다.
자세히 보면 디더링이 적용된 RGB565 버전과 그렇지 않은 버전 모두에서 색상 밴딩 현상이 있다는 것을 알 수 있습니다. 이러한 밴딩 현상은 빨간색 이미지에서 가장 두드러집니다.
따라서 변환된 이미지와 색상 형식에 항상 주의를 기울이고, 필요할 경우 원본 이미지를 변경하거나 다른 색상 형식을 선택하는 것이 좋습니다.
성능
앞에서 언급한 이미지 형식은 모두 그리기 작업의 “용이성”에 최적화된 것입니다. 이 말은 별다른 변환 없이도 이미지를 프레임버퍼로 어느 정도 복사할 수 있다는 것을 의미합니다.
이는 의도적인 것으로, TouchGFX가 마이크로컨트롤러에서 자연스러운 그래픽을 구현할 수 있는 이유 중 하나입니다.
TouchGFX를 사용해 UI를 설계할 때는 .png 이미지를 사용하지만 이후 각 이미지는 위에서 자세히 설명한 것처럼 컴파일 단계에서 효율적인 이미지 형식 중 하나로 변환됩니다.
알파 블렌딩
런타임에서 이미지 데이터 복사는 일반적인 CPU 복사 작업을 통해, 혹은 MCU 기능을 사용해 이루어집니다. 이때 이미지에 완전히 투명하지 않거나 불투명한 픽셀이 포함되어 있으면 해당 픽셀을 배경에 알파 블렌딩 처리해야 합니다. 일부 STM32 MCU에서는 이러한 블렌딩 기능이 하드웨어를 통해 지원됩니다.
기타 이미지 형식
런타임에서 다른 이미지 형식, 예를 들어 .jpg나 .png 같은 압축 이미지 형식이 필요하다면 TouchGFX에서 지원되는 동적 비트맵 기능을 이용할 수 있습니다.