비디오 스트림의 빠르고 무손실 압축


14

고정식 카메라에서 나오는 비디오가 있습니다. 해상도와 FPS는 모두 매우 높습니다. 내가 얻는 데이터는 Bayer 형식이며 픽셀 당 10 비트를 사용합니다. 내 플랫폼에는 10 비트 데이터 유형이 없으므로 원본 데이터는 16 비트 워드를 사용하여 메모리에 저장됩니다. 네트워크를 통해 데이터를 전송하기 전에 데이터 의 무손실 압축 을 구현하고 싶습니다 .

  • 카메라가 움직이지 않기 때문에 연속 프레임의 큰 부분은 거의 동일하지만 피할 수없는 노이즈로 인해 여전히 완전히 그렇지는 않습니다. ).
  • 높은 FPS로 인해 변경되는 부분조차도 두 개의 연속 프레임간에 크게 변경되지 않습니다.
  • 그러나 카메라가 약간 흔들리는 것처럼 보입니다. 정지 된 물체조차도 이미지 공간에 아주 적지 만 여전히 그렇습니다.
  • 압축은 즉석에서 수행해야하므로 많은 프레임을 수집하고 모두 압축 할 수는 없지만 1 프레임을 다시 참조하여 참조로 사용할 수 있습니다.

위의 내용을 토대로, 첫 번째 생각은 데이터를 비트 패킹하여 6 워드의 중복 비트가 모든 단어에 낭비되는 것은 아닙니다. 그러나 엔트로피 코딩 (예 : 허프만 등)을 사용하면 중복성이 자동으로 고려되므로 추가 패킹이 필요하지 않다고 생각했습니다. 그래서 나는 다음을 수행했습니다.

  • 두 개의 연속 프레임간에 이진 차이가 발생했습니다. 원래 데이터 범위는 0 ~ 1023 (예 : 부호없는 10 비트)입니다. 차이 데이터가 서명되고 범위가 -1023 ~ 1023으로 증가하지만 데이터 변동 (또는 올바른 수학 용어)이 원래 데이터보다 훨씬 작아집니다. 실제로, 대부분의 값은 놀랍게도 0에 가깝지 않습니다. .
  • 차이에 대한 응용 쌀 코딩. 내가 이해 한 바에 따르면, 주로 작은 숫자 값의 데이터 세트에 적합한 선택처럼 보입니다.

이것은 1280x720 프레임의 크기를 약 60 % 줄이며 테스트 시스템 (단일 코어의 VirtualBox에있는 Linux)은 초당 최대 40 번의 압축을 수행 할 수 있습니다 (많은 최적화없이). 그렇게 크지는 않지만 합리적이라고 생각합니다.

더 좋은 방법이 있습니까? 내가 저지른 일반적인 실수는 무엇입니까? 내가 놓친 일반적인 단계는 무엇입니까? 더 높은 해상도의 프레임을 나중에 사용할 수 있습니다. 더 큰 프레임 크기에 대해 더 나은 압축률을 기대해야합니까?

UPD .:

  • 내가 사용 이 라이브러리 쌀 인코딩을. 라이브러리는 매우 느립니다 (저자 자신이 실제 사용하기보다는 학습용으로 설명). 예를 들어 루프에서 비트를 하나씩 읽고 쓰고 성능을 저하시킵니다. 처음에는 ~ 20 FPS 만 받았고, 매우 기본적인 최적화 후 40FPS가되었고 (위에보고 된 바와 같이) 나중에 좀 더 최적화하면 80이되었습니다. 이는 벡터화없이 단일 i7 코어에 있습니다.
  • 그러나 벡터화에 관해서는 불행히도 라이스 코드를 벡터화하는 방법을 생각할 수 없었습니다 (가능한 경우조차 알지 못합니다-라이스 코드에 대한 데이터를 찾을 수 없었습니다. 순차적이며 효율적으로 벡터화 할 수 없으므로 라이스 코드 및 기타 가변 길이 코드에 적용될 수 있습니다).
  • 또한 완전히 다른 접근법을 시도했습니다. 데이터를 작은 조각으로 분할하고 (예 : 64 픽셀 조각) 간단한 제로 억제를 사용하십시오. 우리는 블록에서 가장 큰 숫자를 찾아서 그것을 블록의 시작 부분에 나타내는 데 필요한 비트 수를 쓰고 (필자의 경우 4 비트가 더 필요했습니다) 블록의 모든 숫자를 같은 수로 줄입니다. 비트. 압축률은 나쁠 것으로 예상했지만 조각이 작 으면 소음 스파이크가 많지 않기 때문에 이진 차이가 값당 4 ~ 6 비트와 같이 줄어들 수 있으며 실제로는 Rice 코드보다 약 5 % 더 나쁘지만 약 2 배 빠릅니다 (예 : 160 FPS). 나는 벡터화를 시도했지만 벡터화에 다소 짜증이 났기 때문에 약 1.8 배 더 빠른 속도를 달성 할 수 있었기 때문일 수 있습니다.

음수에는 선행 0이 없으므로 이진 차이 후 쌀 / 제로 억제 전에 지그재그 인코딩 을 적용했습니다 .


10 비트 모드를 지원하는 h264 와 같은 표준 코덱을 사용할 수 있습니다 . "-crf 또는 -qp를 0으로 설정하면 x264는 무손실 모드에서 -preset 설정이 속도 / 크기 비율에만 영향을 미칩니다." (하지만 실시간 성능을 관리
할지 모르겠습니다

@CodesInChaos, 두 프레임 만에 많은 일을 할 것입니까?
Headcrab

아마도 더 중요한 것은 표준 코덱이 Bayer 이미지를 인코딩 할 수 있습니까? 내가 실수하지 않으면 Bayer를 RGB로 변환하는 것은 보간을 포함하므로 돌이킬 수 없습니다.
Headcrab

답변:


4

시간 예측은 있지만 공간은 없습니다. 속도를 희생하여 압축률을 높이려면 현재 프레임의 현재 픽셀 위와 왼쪽에있는 픽셀을 예측 자로 사용하고 이전 프레임의 동일한 위치에있는 픽셀을 사용할 수 있어야합니다. 위와 왼쪽 만 보는 이유는 이전 프레임 만 보는 이유와 같습니다. 이미 디코딩 한 데이터에만 의존하고 유지해야하는 데이터의 양을 제한하려고합니다.

라이스 코드는 효율성과 속도 사이에서 좋은 트레이드 오프 일 수 있지만 정적 Huffman 코드 (비디오 데이터 샘플에서 사전 계산 된)가 더 효율적이고 똑같이 빠를 수 있습니다.

속도 는 컴파일러가 자동 벡터화 할 수 있도록 올바른 컴파일러 플래그 및 코드 패턴을 사용 하거나 벡터 내장 함수 또는 어셈블리 를 사용하도록 코드를 직접 작성하여 코드 가 벡터화 되는지 확인하십시오 .

마지막으로, 픽셀 당 8 비트로 드롭 다운이 가능합니까? 분명히 그것은 "무손실"의 영역을 떠나고 있지만 압축 된 출력의 크기를 줄일뿐만 아니라 벡터화 된 코드를 사용하여 처리량을 최대 2 배까지 증가시킬 수 있습니다.


10bpp를 8로 줄이는 것은 불가능하지만 UTF-8이 문자를 저장하기 위해 1 또는 2 바이트를 사용하는 것과 거의 같은 방식으로 더 적은 비트로 델타를 저장할 수 있습니다. 델타가 항상 거의 0이라면, 10 비트가 모두 변하는 것을 보는 것은 매우 드물기 때문에 1 또는 2 바이트를 저장하여 저장할 수 있습니다.
gbjbaanb

@gbjbaanb는 Rice 코딩이 달성 한 것입니다. 대부분의 델타는 작으므로 몇 비트 만 사용합니다.
hobbs

@ hobbs, "공간 예측"이란 픽셀 값 x5을 차이로 바꾸는 것과 같은 것을 의미 (x5 - x4)합니까?
Headcrab

@Headcrab-이전에 사용한 접근법은 이전 픽셀의 중간 값과 현재 프레임에서 위와 왼쪽의 픽셀을 사용하는 것입니다.
Jules

@Jules 픽셀이 주변 픽셀의 중간 값으로 대체되면 원래 값을 복원 할 수 있습니까?
Headcrab

0

기존의 압축 및 압축 해제 구현을 사용하는 것이 가장 좋습니다. 기존 구현은 HuffYUV 코덱과 비슷해 보이 므로 그것이 제대로 작동하는지 확인하는 것이 좋습니다.


libx264는 "사전 초고속는 ..."역사적으로 FWIW 아주 잘 날 역임했다
rogerdpack

@ rogerdpack-손실없는 인코딩에 대한 libx264의 설정은 H.264와 호환되지 않는 출력을 생성하고 일부 플레이어에서 중단된다는 점에 주목할 가치가 있습니다. 그러나 적어도 OP의 응용 프로그램에는 유용 ​​할 수 있습니다.
Jules

재미 있습니까? 버그 신고? 또한 HuffyYUV로 인코딩 된 비디오는 아마도 "유일한 플레이어에게 친숙하지 않다"고 생각합니다. :)
rogerdpack
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.