Programming/IoT_Embedded

왜 OpenCV는 BGR 포맷을 쓸까?

이세우 2019. 9. 16. 11:16

OpenCV를 처음 접하고나서 제가 가졌던 첫 의문이었습니다.

왜 OpenCV는 BGR 포맷을 쓸까? 대부분의 사람들에게 익숙한 RGB를 쓰지 않고 말이죠.

이 때문에 RGB 포맷으로 바꾸려면 파이썬의 경우 아래와 같은 코드를 꼭 거쳐야 하는 불편함이 있습니다.

rgb = bgr[:,:,::-1]

저는 의문이 한번 들면 그게 쓸모가 있든 없든, 문제 해결에 도움이 되든 안되든, 그 이유를 찾아야 속이 후련해 지는 타입입니다. 물론 이 주제에 대해 찾아 본건 아주 오래전이기는 합니다만, 머리가 복잡한 일이 생겨서 오랜만에 과거에 메모해두었던 노트들을 뒤젹이다 이 주제가 눈에 띄어서 포스팅해 봅니다.

일단 구글링을 했더니 OpenCV와 관련해서 많은 포스팅을 하는 learnopencv.com의 사타야 말릭 박사(Dr. Satya Mallick) 의 글을 찾을 수 있었습니다. 본문은 아래 링크에서 읽을 수 있습니다.


본문을 요약하면 사타야 말릭 박사는 한 컨퍼런스에서 OpenCV의 창시자인 그레이 브라드스키 박사(Dr. Gray Bradski)를 만났고 그에게 왜 RGB가 아닌 BGR을 쓰냐고 물었다고 합니다. 그랬더니 그에 대한 대답은 “왜 미국 철도 표준이 4피트 8.5 인치 인가?”라는 질문으로 되돌아 왔다고 합니다. 
이게 무슨 말이냐면 미국이 철도 표준을 정할때 무슨 대단한 이유가 있어서 4피트 8.5인치로 정한것이 아니라 열차 이전에 주로 사용했던 마차의 폭에 마춰서 정했다는 겁니다. 결국, 브라드스키 박사도 BGR로 정한데는 별다른 이유가 있던게 아니라 그걸 정하던 시절 초창기 카메라 산업 개발자들이 BGR을 많이 썼기 때문에 그 자신도 그냥 아무 생각없이 BGR을 선택했다는 거죠.

네, 대충 이해가 가는 대목입니다.

위 링크의 본문은 대략 이 정도를 서술하고 마칩니다. 그런데 저는 아직 조금 답답했습니다.
왜 초창기 카메라와 같은 영상 기기 개발자들 사이에서는 RGB보다 BGR을 많이 썼을 까요?

그것은 바로 엔디안(Endianness)와 관련이 있다고 할 수 있습니다.
CPU에 따라서 값을 메모리에 저장하고 읽을 때,  MSB 즉 큰 값을 먼저 쓰는 빅엔디안과 LSB 즉 작은 값을 먼저 쓰는 리틀엔디언 방식이 있는데, 인텔에서 만든 x86계열의 CPU는 리틀엔디언을 따릅니다.
참고로 OpenCV는 인텔에서 시작했습니다.

예를 들어 0x123456이라는 값을 빅엔디언으로 저장하면 0x123456 순으로 저장되지만 리틀엔디언으로 저장하면 0x563412순으로 저장되게 됩니다.

BGR 포맷으로 이루어진 색상 정보는 각 채널당 8비트로 이루어 지고 3개의 채널을 사용하므로 24비트 즉, 0xBBGGRR가 필요합니다.  24비트 단위의 입출력은 효과적이지 않으니 메모리에 저장할때 unsigned 32비트를 사용하는것이 일반적인데 이렇게 되면 0x00BBGGRR 가 됩니다. 이 값을 x86 계열의 CPU 처럼 리틀엔디언을 사용해서 저장하면 메로리에는  0xRRGGBB00가 저장됩니다.

이렇게 저장된 값을 메모리에 직접 접근해서 읽어 들이는 디스플레이 장치, 카메라 등의 영상 하드웨어에서는 CPU와 무관하게 지정된 엔디안으로 앞에서 부터 읽어 들이면 자연스럽게 RGB로 읽히기 때문에 BGR 포맷이 초창기 영상 기기 관련 하드웨어 개발자들에게 자연스레 널리 사용되었다고 볼 수 있습니다.

BGR 포맷과 엔디안과의 관계에 대한 추가적인 의견은 아래의 스택오버플로우 링크에서도 보 실 수 있습니다.