1. 압축의 종류와 방법
우리 주변에 존재하는 모든 아날로그 신호는 무한합니다. 빛과 바람, 소리. 모든 것들이 특정 기준 없이는 측정할 수도, 분해할 수도 없죠. 이 무한한 아날로그 신호를 단 하나도 빠짐없이 디지털 신호로 바꿔서 데이터에 기록한다면 사진 한 장만으로도 매우 큰 용량이 나오게 될 것입니다. 가장 보편적으로 사용되는 HD 해상도의 영상을 압축 없이 저장한다면, 1분짜리 영상이더라도 약 12GB가 나오게 될 거예요. 영상의 품질을 더 높여서 4K 해상도의 영상을 문제없이 볼 수 있는 10bit 수준으로만 저장하더라도 1분에 약 20GB가 됩니다. 만약 이 수준으로 영화 한 편을 담는다면 용량은 약 2TB가 될 것이기 때문에 인류는 하드디스크로 탑을 쌓아 화성에 가게 될지도 모르겠습니다. 이것을 해결하기 위해 코덱 안에는 데이터를 압축하는 기술이 개발되어 들어가 있습니다. 코덱은 너무나도 거대한 디지털 신호를 필요한 정보만 걸러서 적절하게 압축하는 역할을 해요. 여기서 중요한 건 '적절한 압축'입니다. 데이터 양을 줄이되, 최소한 우리 눈이 알아차릴 수 없을 정도의 품질을 가지며 데이터를 줄여나가는 것이 관건 이예요. 영상 이미지 압축에는 대표적으로 Intra-Frame이라 불리는 공간압축과 Inter-Frame인 시간압축. 두 가지 방법이 있습니다.
2. 공간압축(Intra-Frame)
눈은 우리 신체의 감각 기관 중에서 가장 민감한 기관 중 하나입니다. 원시 인류가 살아남기 위해서는 시각 정보에 가장 의존해야 했기 때문에 민감해질 수밖에 없었을 거예요. 우리 눈은 그 무엇보다 섬세하지만 그렇다고 완벽하지는 않습니다. 착시나 잔상, 그리고 특정 밝기나 색영역에 취약하다는 점만 봐도 그나마 '덜 민감한 영역'이 있다는 거죠. 공간압축은 이러한 눈의 허점을 이용해서 유사한 데이터를 합치거나 인식하지 못하는 영역을 제거하면서 이뤄집니다. 다만 시간압축과는 다르게 모든 프레임의 데이터가 온전하게 존재합니다.
공간압축은 크로마 서브샘플링(Chroma Subsampling), DCT(Discrete Cosine Transformation), 양자화(Quantization), 부호화(Encoding)과정을 거쳐서 진행됩니다.
2-1. 크로마 서브 샘플링(Chroma Subsampling)
먼저 이미지가 준비 되었다면, RGB였던 색공간을 YCbCr(유사 YUV)로 변환하는 것부터 시작됩니다. 빛의 삼원색인 빨강R, 초록G, 파랑B을 적절히 조합해서 색을 만드는 방식에서 밝기와 색상을 분리시켜서 색을 만드는 방식으로 바꾸는 거예요. 이는 인간이 색을 인식할 때 RGB를 떠올리지 않고 밝기와 색상, 채도를 종합해서 이해하는 원리를 차용했기 때문입니다. 지금 당장이라도 특정 색깔을 보면 RGB의 비율보다 이 색의 밝기는 어떤지, 색상과 색의 농도는 얼마나 진한지를 보고 인식할 테니까요.
Y'Cb'Cr에서 Y는 밝기(휘도), Cb는 밝기 대비 파란색의 색차, Cr은 밝기 대비 빨간색의 색차입니다. 이렇게 밝기와 색차를 분리하는 이유는 눈이 밝기보다 색상에 대한 변화를 덜 민감하게 느끼기 때문이에요. 즉 밝기가 조금이라도 변하거나 밝기 정보의 품질이 떨어지면 우리 눈이 바로 알아차리는 반면에, 색상 정보를 덜어낸다고 해서 큰 변화를 느끼지 못한다는 겁니다. 심지어 밝기대비 색정보를 2배 이상 덜어내도 시청하는 것에는 문제없습니다.따라서 밝기 정보는 그대로 두고 Cb, Cr의 정보를 줄이기 위해 인접한 픽셀들을 그룹화해서 비율에 따라 어떤 픽셀을 버릴지 선정하고 남은 픽셀이 그룹을 대표하게 되는 거예요. 코덱의 종류에 따라 YCbCr 샘플링 비율은 4:4:4, 4:2:2, 4:1:1, 4:2:0으로 압축하고, 그다음 단계로 넘어갑니다.
2-2. 블록 스플릿(Block Split)
서브 샘플링이 완료되면 분리된 휘도(Y)와 색차신호(CbCr)는 샘플링 비율에 따라 특정크기의 블록으로 분할됩니다. 휘도(Y) 채널은 항상 8x8 블록으로 나뉘고, 만약 샘플링 비율이 4:4:4일 경우 8:8, 4:2:2은 16x8, 4:2:0은 16x16으로 나뉘게 돼요. 즉, 샘플링 비율 4:4:4의 휘도채널의 블록이라면 64개의 픽셀로 이루어져 있고, HD영상이라면 32400개의 블록으로 나뉘는 겁니다. 구역을 세부적으로 나눠서 분석하고 처리하기 위해서 지방자치제를 하는 거죠.
2-3. 이산 코사인 변환, DCT(Discrete Cosine Transformation)
수만, 수십만 개로 나뉜 블록은 각 블록마다 개별적으로 분석하고 압축하기 위한 과정에 들어갑니다. 이때 2D 화면 위 공간 영역에 존재하는 픽셀의 에너지 성분을 주파수 영역으로 변환하고, 고주파와 저주파를 분리하는 작업을 진행해요. 이를 DCT, 즉 '이산 코사인 변환'이라고 하는데요, 꽤나 복잡하고 어려워 보이지만 뜰채를 이용해 달걀흰자와 노른자를 분리해서 따로 요리하는 것과 같다고 생각하면 됩니다. 공간 영역에서는 각 픽셀마다 에너지 성분이 불규칙적으로 배열되어 있지만, 이를 주파수 영역으로 바꾸고 저주파와 고주파를 분리하면 압축하기가 훨씬 수월 해집니다. 굳이 주파수로 나누는 이유는 이것 역시도 우리 눈의 특성과 관련이 있어요. 우리는 작은 변화보다 큰 변화에 훨씬 더 민감하게 반응합니다. 잔잔한 호수에는 아주 작은 돌멩이만 던져도 큰 물결이 일어나는 것처럼 말이죠. 반면에 파도가 거칠게 치고 있는 바다에는 아무리 큰 돌을 던져도 물결이 치는 것을 알아차리가 어렵습니다.
위 하늘 이미지를 보면 하늘 부분에 작은 점이라도 찍히면 우리는 금방 알아차릴 것입니다. 인접한 픽셀 간의 차이가 작기 때문이죠. 반면 나뭇잎이 빼곡하게 채워진 부분, 특히 하늘과 나무의 경계 부분은 인접한 픽셀간의 차이가 크기 때문에, 점이 생긴다고 해서 고요한 하늘만큼 알아 차리기는 어려울 겁니다. 이렇게 하늘과 같이 인접 픽셀간의 차이가 작은 부분은 저주파, 경계면과 같이 인접 픽셀간의 차이가 큰 부분은 고주파를 가지게 됩니다. 이제 조금은 이해가 되시죠? 주파수 영역에서 고주파와 저주파로 나누고, 알아차리기 힘든 '고주파' 영역만 정보만 덜어내어 압축하면 좋은 품질을 유지하면서 효율적인 데이터 압축을 이뤄낼 수 있을 겁니다. 그리고, 바로 이 DCT 변환을 사용해서 공간 영역을 주파수 영역으로 바꾸고, 저주파와 고주파로 나누는 거예요.
8x8 블록 내에 있는 64개의 픽셀 중 우상단에 있는 가장 첫 번째 픽셀에 저주파 영역이 몰리게 됩니다. 그리고 우하단으로 갈수록 고주파 영역이 분포하게 돼요. 저주파 영역이 몰려있는 우상단 부분을 DC계수, 나머지 63개의 값을 AC계수라고 합니다. 거의 대부분의 이미지가 인접한 픽셀이 비슷한 색으로 존재하기 때문에 DC계수에 값이 몰리게 되고, 이 DC계수는 해당 블록의 평균 색상값을 가지게 됩니다. 실제로 DCT변환은 굉장히 어렵고 복잡한 과정을 거치지만, 개발 목적이 아니라면 주파수를 나눠 고주파와 저주파로 분리시킨다는 개념만 알고 있는 것으로 충분해요.
2-4. 양자화(Quantization)
이전 비트뎁스를 설명할 때 표본화와 양자화에 대해서 간단히 설명했었습니다. 양자화는 특정한 값이 나오면 정해진 양자화 설정에 따라 기준값에 가장 근접한 값으로 매칭되는 것이라 했습니다. DCT 변환으로 각 블록마다 산출된 주파수 영역에 대해 양자화를 진행하면서 불필요한 데이터를 줄이게 됩니다. 여기서 중요한 건 우리 눈이 민감하게 반응하는 '저주파' 영역보다 손실이 발생해도 알아차리지 못하는 '고주파' 영역을 더욱 적극적으로 덜어낸다는 사실이죠. 각 주파수 영역에 대해 설정된 양자화 테이블(행렬)로 나눈 후에 반올림합니다. 양자화 테이블은 양자화를 진행할 때 사용되는 행렬로 이루어진 표입니다. DCT 변환 이전에 나누었던 픽셀 블록과 같은 행렬로 구성되어 있어요. 양자화 테이블은 정해진 비트뎁스를 고려해서 값이 정해지고, 비트뎁스가 올라갈수록 더 높은 품질을 위해 압축률이 낮아지게 됩니다.
양자화 테이블은 저주파 성분이 몰려있는 좌상단, DC계수 부분에는 가장 낮은 값이 할당되어 있으며, 고주파 성분으로 내려갈수록 높은 값이 할당되어 있습니다. 양자화 테이블이 적용되면 할당된 값으로 나누고 반올림을 하게 됩니다. 양자화가 진행된 결과를 보면 저주파 영역인 DC계수를 제외한 나머지 고주파 영역은 대부분 0으로 반올림되었음을 확인할 수 있어요.
2-5. 델타 코딩(Delta Encoding)
모든 블록이 양자화까지 완료되었다면, 이제 양자화된 값들을 최종적으로 압축하고 저장하는 과정만 남았습니다. 양자화된 DC계수와 AC계수는 완전히 다른 특성을 가지고 있기 때문에 각자 다른 방법으로 압축됩니다. DC계수와 AC계수를 압축하는 방법에는 여러 가지가 있지만, 공간 압축 방식을 사용하는 가장 대표적인 비디오 코덱인 ProRes를 예로 들어 설명해보도록 하겠습니다. 단, 기술을 공개하는데 매우 폐쇄적인 애플이기 때문에 공식 문서에는 나와있지 않지만 다른 연구 문서에 나와있는 자료를 참고했으니 개념만 이해 해주시면 좋겠습니다.
먼저 DC계수는 델타 코딩을 사용해서 압축됩니다. 델타코딩은 데이터의 연속된 값의 차이를 나타내어 효율적으로 압축하는 방식입니다. 처음에 설명했던 것처럼 서로 인접한 픽셀은 비슷한 색정보를 가지고 있을 가능성이 높기 때문에 DC계수의 값도 비슷할 것입니다. DC계수가 곧 해당 블록의 평균 색상값을 나타내기 때문이에요. 따라서 연속된 블록 사이에 중복된 값을 제거하고 그 차이만 저장하면 데이터를 더 효율적으로 압축할 수 있습니다. 하나의 이미지 안에는 이미 수많은 8x8 크기의 블록이 나누어져 배열되어 있습니다. 그리고 각 블록의 DC계수는 하나씩 존재해요. 현재 DC계수 값에서 이전 DC계수 값을 뺀 나머지만 저장하는 방식으로 데이터를 압축하는 방법입니다. 위 이미지처럼, 980(10bit)보다 4(3bit)를 저장하는 것이 훨씬 더 적은 데이터를 차지하게 되는거죠. 이렇게 하면 중복된 값을 제외한 두 값의 차이에 대한 데이터만 저장할 수 있게 되고, 첫 블록의 DC계수 값을 알고있기 때문에 나중에 디코딩을 할 때 이전 DC계수 값을 더하고 예측해서 원래 값을 복원할 수 있게됩니다.
2-6. 엔트로피 코딩(Entropy coding)
AC계수를 압축하는 데에도 여러가지 방법이 있지만, 일반적으로 Intra-Frame(공간압축)은 무손실 압축 방식인 엔트로피 코딩(Entropy Coding)을 사용하여 부호화가 이루어집니다. 엔트로피는 열역학 2법칙으로 자연현상 속 물질의 상태나 변화의 방향을 설명하는 개념입니다. 시간이 흐름에 따라 엔트로피의 총량은 언제나 증가한다는 것이죠. 우주적 관점에서 엔트로피가 가장 낮은 단계는 빅뱅이 일어나기 전 존재했던 모든 물질이 완벽하고 질서 정연하게 배열된 상태였습니다. 그러나 빅뱅 이후 시간 지나면서 중력장을 형성하는 천체와 물질의 형성 및 분해과정이 일어나면서 우주는 무한히 확장되며 엔트로피가 증가하고 있어요. 따라서 모든 우주와 자연이 흐르는 방향은 무질서, 즉 엔트로피가 증가하는 방향으로 가는 것이죠. 따뜻한 커피가 식는 것, 불이 붙은 장작이 재가되는 것 모두 엔트로피가 증가하는 것입니다. 그리고 시간을 되돌려 잿더미를 원래 장작으로 되돌릴 수 없듯이 엔트로피는 절대 낮아질 수 없어요.
하지만 엔트로피 코딩은 높은 엔트로피 상태에 있는 데이터를 압축함으로써 엔트로피를 줄이는 것을 목표로 합니다. 정보학의 측면에서 엔트로피는 정보를 담고 있는 정도, 불확실성을 측정하는 용도로 사용됩니다. 따라서 불필요한 하거나 반복되는 정보를 제거해서 데이터를 효율적으로 표현하고 압축하는 것이라 할 수 있습니다. 엔트로피 코딩에는 대표적으로 허프만 부호화(Huffman Coding), 가변 부호화(VLC), 런렝스 부호화(Run-Length Encoding) 등이 있지만 이 설명에서는 ProRes가 사용하고 있을 것으로 추측되는 런렝스 부호화에 대해 알아보도록 하겠습니다.
런렝스 부호화(Run-Length Encoding)는 데이터에서 같은 값이 연속해서 나오거나 패턴화 되어서 나올 경우, 반복되는 개수와 값으로 표현하는 방법입니다. 예를들어 "AAAAABBBBCCC"와 같은 문자열이 있다고 해보겠습니다. 이 문자열을 런렝스 부호화를 사용하면 "5A4B3C"로 표현할 수 있어요. 이렇게 되면 반복되는 값의 개수와 데이터 값 자체만을 저장하기 때문에 손실없이 데이터를 압축할 수 있습니다. 0이 연속되어 나오는 63개의 AC계수를 처리하는데 아주 유용한 방식이죠.
런렝스 부호화를 진행하기 전에 먼저 AC계수를 나열해보려 합니다. 이 때에는 zigzag scanning 기법이 사용됩니다. 지그재그 스캐닝은 8x8형태의 블록을 지그재그로 읽어서 값을 나열하는 방법입니다. 이 방법으로 값을 읽었을 때 유사한 값이 연속으로 나타나기 때문이에요. ProRes에 사용되는 런렝스 부호화의 결과는 연속되는 0을 기준으로 (Runlength, Size)(Amplitude) 와 같은 형식으로 부호화 됩니다. 위 형식은 (연속된 0의 개수, 데이터 크기)(해당 계수의 값) 으로 정리할 수 있습니다.
마지막으로 이 데이터는 허프만 부호화와 같은 무손실 압축에 사용되는 엔트로피 코딩을 한번 더 거쳐 최종적으로 압축, 저장하면 공간압축 방식의 인코딩은 끝나게 됩니다. 공간압축 방식을 사용하는 가장 대표적인 코덱에는 ProRes, DNxHR 등이 있습니다. 이들은 모든 프레임에 대해 정직하게 데이터를 가지고 있기 때문에 뛰어난 재생효율로 편집용 코덱에 많이 사용됩니다. 그리고 압축을 덜하거나, 아예 진행하지 않으면 모든 프레임이 높은 품질로 온전한 데이터를 갖게 됩니다. 그리고 이들을 매개코덱, 혹은 마스터링 코덱이라고 해요.
코덱의 종류와 용도에 대해 더 자세한 내용은 코덱에 관한 자세하고 직관적인 설명들에 있습니다.
3. 시간압축(Inter-Frame)
매년 옥수수 농사를 짓기 위해 넓은 대지에 씨앗을 뿌립니다. 관리를 열심히 해서 매년 풍년을 이뤘어요. 그런데 정말 이상하게도 특정 지역에 뿌린 씨앗만 옥수수가 자라지 않았습니다. 지난 번에는 분명 다른 이유가 있을거라 생각해서 다시 씨앗을 뿌리고 관리를 열심히 해보았지만 몇년동안 정확히 똑같은 지역만 싹이나지 않는거죠. 어떤 방법을 사용해도 옥수수가 자라지 않는 땅이라 판단해서 다음 해부터는 그 지역에는 더이상 씨앗을 뿌리지 않습니다. 씨앗 뿐만이 아니라 옥수수를 재배하는데 들어가는 자원과 비용을 낭비할 수는 없기 때문이죠. 옥수수가 자라지 않는 땅에는 굳이 씨앗을 뿌리지 않는 것이 당연히 현명한 방법입니다. 그리고 이 개념을 그대로 영상 압축 기술에 적용하면 시간압축, 즉 Inter-frame 방식이 됩니다.
인터프레임은 연속된 프레임 속에서 공통점을 찾아내고 분석해서 이미지의 유사한 부분에 대해서는 압축하지 않고 좌표만 설정해두는 방식으로 영상을 구성하는 방법입니다. 즉, 영상의 프레임 간에 움직이는 부분만 처리하고, 나머지 움직이지 않는 부분은 이전 프레임의 정보를 가져와 대체하는 방식으로 압축하는 거예요. 시간압축을 위해 영상 이미지 프레임은 다음과 같이 3가지의 종류로 나뉩니다.
3-1. IBP
처음에는 당연히 프레임에 대한 분석이 되지 않았기 때문에 프레임의 모든 부분을 다 저장해야할 겁니다. 모든 정보를 가진 이 프레임이 Keyframe이 되고, 이를 I-frame(Intra-coded frame)이라고 합니다. I-frame은 위에서 설명했던 공간압축 방식을 사용해서 압축되고 저장됩니다.
키프레임인 I-frame을 기준으로 움직임이 있을 때 그 움직인 부분만 압축해서 저장한 프레임을 P-frame(Predictived-coded frame)이라고 합니다. 예를들면 날아가는 공의 시작점인 I-frame을 기준으로 공이 도착하는 지점이 P-frame이고, 이 P-frame은 움직임이 있었던 공만 따로 저장한다는 것이죠. 나머지 움직이지 않았던 부분은 I-frame의 정보를 가져와 사용합니다. 원래 이미지에서 움직임이 존재하는 일부만 처리하기 때문에 데이터를 효과적으로 줄일 수 있는거죠.
마지막으로 키프레임인 I-frame, 이전 키프레임을 기반으로 움직인 부분만 압축하는 P-frame 사이 앞뒤 프레임을 참조하여 추측한 데이터로 저장하는 B-frame(Bidirectionally predictive-coded Frame)이 있습니다. 날아가는 공의 시작지점과 도착지점 사이를 예측하여 공이 날아가는 과정의 프레임을 저장합니다.
3-2. GOP(Group Of Pictures)
이렇게 시간압축 방식을 사용하는 코덱의 모든 프레임은 IBP로 구성되어 있습니다. I-frame이 먼저 키프레임을 정하고 해당 프레임의 모든 데이터를 저장하면, 그 뒤에 P-frame이 I-frame을 기반으로 프레임 안의 변화된 부분만 분석하여 압축, 기록해요. 그리고 I-frame과 P-frame 사이를 B-frame이 앞, 뒤로 분석하고 추측하면서 움직인 부분만 다시 압축을 진행합니다. 보통 I/B/P 프레임은 10~15프레임으로 이루어져 있는데, 이 하나의 프레임 묶음을 GOP(Group Of Pictures)이라고 합니다. 한묶음의 GOP 안에 100% 온전한 이미지가 저장되어 있는 프레임은 I-frame 밖에 없기 때문에 데이터를 드라마틱하게 줄일 수 있는 거예요. 하지만 재생을 할 때마다 I-frame에 있는 정보를 참조해서 가져오기 위해 연산을 해야하고, 갑자기 다른 부분을 재생하려고 하면 훨씬 더 많은 정보를 처리해야하기 때문에 재생효율이 떨어지게 됩니다. 물론 하나의 영상을 재생 하는 데에는 전혀 문제가 없지만 인터프레임 방식의 영상으로 편집을 하다가 편집점이 생기게 되면, 이 때에는 IBP 프레임을 재구성 해야하기 때문에 컴퓨터가 처리해야 할 일이 또 생기게 됩니다. 아무리 좋은 사양의 컴퓨터라고 해도 수백개의 파일, 수천개의 편집점이 생긴다면 계속 피로가 쌓여서 언젠가 대환장 파티가 일어나게 될 거예요. 대표적으로 이전에 설명했던 H.264, H.265가 시간압축 방식을 사용해서 저장하고 있습니다.
'nonlinear > 영상기술' 카테고리의 다른 글
오프라인 편집: 무거운 영상을 가볍게 편집하기(EDL,XML,AAF) (1) | 2024.04.08 |
---|---|
재미로 알아보는 시네마 카메라 계급도 (0) | 2024.04.06 |
코덱에 관한 자세하고 직관적인 설명들 (0) | 2024.03.30 |
프레임레이트와 비트레이트(Framerate, Bitrate) (0) | 2024.03.03 |
비트뎁스(Bit Depth): 화면 뒤에 숨겨진 보석들 (1) | 2024.02.12 |