Nibnib: 압축 해제 속도를 극한까지 끌어올린 이미지 압축

Nibnib: Image compression with extreme decompression speed

github.com/raphlinus ▲ 185 댓글 32 raphlinus

요약

Nibnib은 픽셀당 약 6사이클 예산에 맞춰 입력 1바이트로 픽셀 2개를 복원하는 이미지 포맷입니다.

개발자 raphlinus가 RP2350 마이크로컨트롤러의 DVI 화면 출력에서 화질과 성능이 어디까지 가능한지 실험하다 만들었습니다. 이 칩에서는 픽셀을 가져와 팔레트(색상표)를 조회하고 저장하고 나면 남는 사이클이 거의 없습니다.

왜 중요한가

  • 화면에 내보내는 속도에 맞춰 즉석에서 풀어야 하는 기기에서 일반 팔레트 이미지보다 나은 화질을 노립니다.
  • 어려운 계산을 인코더로 몰았기 때문에, 디코더를 바꾸지 않고 인코더만 고쳐도 화질을 높일 수 있습니다.

핵심 내용

  • 팔레트에 절대 색상 대신 직전 픽셀과의 차이값을 담아, 색이 완만하게 변하는 영역의 화질을 높였습니다.
  • 1바이트로 픽셀 2개를 만들므로 픽셀당 4비트로 압축되며, 여기에 헤더와 팔레트 용량이 더해집니다.
  • 인코더는 팔레트 256개 항목을 모두 시험해 오차가 가장 작은 값을 고르고, 남은 오차는 주변 픽셀로 나눠 줍니다.
  • 지금의 인코더는 디코더보다 자릿수 단위로 느리고, 입력 이미지에 맞춰 팔레트를 고르지도 못합니다.
  • 날카로운 경계 오른쪽에 화질 손상이 끌리는 한계가 있고, 메타데이터가 없어 보관용으로도 맞지 않습니다.

HN 반응

  • JPEG과 비교한 수치가 없어 속도를 판단할 수 없다는 비판과, JPEG을 실시간으로 못 푸는 기기가 대상이라는 반론이 맞섰습니다.
  • 여러 이용자가 Amiga의 HAM 화면 모드를 떠올렸고, 작성자는 데스크톱이 아니라 자원이 극히 제한된 기기용이라고 밝혔습니다.

댓글

30개 표시 · 전체 32개
  1. raphlinus HN

    Adafruit Fruit Jam이 있으면 그 보드에서 데모를 돌려 볼 수 있습니다 1. SD 카드에 담긴 640x480 영상을 60fps로 스트리밍할 수 있고, 플래시에 든 정지 이미지도 띄울 수 있습니다.

    HN 분들께 흥미로울 만한 점이 하나 더 있는데, 디코더2는 symbolasm3이라는 새로운 저수준 언어로 작성했습니다. 어셈블리어의 장점(성능을 거의 제약 없이 따져 보고 최적화할 수 있다는 점)에 C의 편의 기능, 특히 이름 붙인 변수와 구조체 필드를 결합하려는 언어입니다.

  2. derefr HN

    특히 이름 붙인 변수와 구조체 필드

    그건 대부분의 매크로 어셈블러에서도 되지 않나요? 아주 오래되고 낡은 어셈블리 코드인데도 매크로 기능으로 구조적 프로그래밍, 심지어 제한적인 OOP까지 하는 걸 본 적이 있거든요.

    (그렇긴 해도 symbolasm은 어떤 매크로 어셈블리보다 1000배는 쓰기 편해 보이고 "개발자의 의도도 함께 전달하는" 느낌이 강합니다. 게다가 프로젝트마다 매크로가 제각각인 것과 달리 한 번 배워 두면 계속 쓸 수 있을 것 같고요.)

  3. raphlinus HN

    매크로 어셈블러가 변수에 대한 레지스터 할당이 일관적인지 확인하려고 흐름 기반 분석까지 한다고는 생각하지 않습니다. 제가 알기로는 기껏해야 레지스터 이름에 범위가 한정된 별칭을 붙여 주는 정도입니다. 물론 제가 놓친 게 있을 수도 있고요. 제가 인용한 관련 연구 말고 다른 걸 아시면 알려 주세요.

  4. hcs HN

    저도 MIPS용 어셈블러를 두고 비슷한 구상을 했습니다. 호출된 스코프 안에서 예약되는 심볼 이름을 쓰고, 어셈블러가 할당을 찾아내거나 오류를 내게(무엇을 스필할지 명시적으로 정하도록) 하고 싶었습니다. 당시(2018년쯤)에는 참고할 만한 사례를 찾지 못했습니다. 결국 어셈블러에 시간을 너무 많이 쓰고 있다고 판단해서 대부분 전역 할당으로 갔습니다.

  5. the-tomster HN

    멋진 프로젝트네요! symbolasm 근사해 보입니다. MenuetOS에서 fasm을 만지작거리며 어셈블러를 이해해 보려고 애쓰던 때가 떠오릅니다.

  6. skiialing HN

    프로젝트 중 적어도 일부는 바이브 코딩으로 만든 거죠? 저장소 몇 곳과 Hacker News 댓글 몇 개에서 LLM을 썼다고 말씀하셨던데요.

  7. raphlinus HN

    이미지 압축도 symbolasm 언어도 처음에는 전부 직접 손으로 코딩했고, 그 뒤로 발전시키는 데 Claude를 썼습니다. 이 부분에 대해서는 복잡한 심경입니다. 기본적으로 LLM이 없었어도 같은 결과를 얻었겠지만 훨씬 오래 걸렸을 겁니다.

    지금 우리 업계의 가장 큰 과제 중 하나는 LLM을 제대로 쓰는 방법, 즉 품질을 지키고 슬롭에 맞서는 방법을 찾는 거라고 생각합니다. 그 일환으로 글은 제가 직접 쓰려고 신경 쓰고 있습니다.

    그래도 LLM을 조금이라도 썼다는 것만으로 거부감이 들 수 있다는 건 충분히 이해합니다. 저도 그렇게 느껴 본 적이 있으니까요.

  8. augment_me HN
    1. 압축 해제 속도를 극단적으로 내세우면서 JPEG과 비교한 수치조차 안 보여 주는 건 의미가 없다고 봅니다.

    2. BCx는 본질적으로 같은 코드북/팔레트 방식인데, 팔레트 항목 두 개 사이를 보간할 수 있어서 더 효율적이고 압축률도 훨씬 높습니다.

  9. DoctorOetker HN
    1. 특정 상황에서 JPEG을 실시간으로 디코딩하지 못하는 플랫폼을 겨냥할 수 있다는 걸 생각하면 의미 없어 보이지만은 않을 겁니다.
  10. wongarsu HN

    어떤 마이크로컨트롤러에서 "JPEG 디코딩 20000ms, Nibnib 디코딩 13ms"라는 벤치마크가 나온다면 그게 왜 의미가 없겠어요? 그런 게 있었다면 훌륭한 벤치마크였을 텐데요.

    문제가 디코딩에 필요한 메모리라면, 저자가 둘 다 돌아가는 가장 작은 하드웨어에서 메모리 수치를 곁들여 벤치마크를 내놓을 수도 있습니다. 아니면 RP2350에서 각 알고리즘으로 디코딩할 수 있는 가장 큰 이미지 크기를 보여 주든가요.

  11. augment_me HN

    저장소에 JPEG 구현의 수치가 있었다면 그게 분명해졌겠죠.

  12. orangeboats HN

    왜요? JPEG 픽셀을 명령어 6개로 디코딩할 수 없다는 건 꽤 분명하다고 생각했는데요.

  13. AlotOfReading HN

    JPEG 디코딩이 메모리 대역폭에 묶여 있다고 하더라도, 혹은 그렇지 않더라도 성능 차이가 얼마나 될지는 놀랍지 않을 것 같습니다. 명령어 수만으로는 대개 좋은 성능 지표가 되지 못합니다.

  14. schobi HN

    빠르다는 건 알겠습니다. 그런데 그 대가로 뭘 내줘야 하나요?

    물론 JPEG보다 훨씬, 훨씬 적겠지만, JPEG은 평균 몇 개쯤이라고 보시나요? JPEG을 편법으로 쓰면 얼마나 낮출 수 있을까요?

    보통은 비트레이트/품질/속도를 그래프로 그립니다. JPEG은 기본 설정으로만 돌려서 새 알고리즘과 비교할 데이터 포인트를 하나만 잡아도 됩니다.

  15. alembic_fumes HN

    필수 링크: https://xkcd.com/2501/

    덤으로 일화 하나 말씀드리면, 저는 이미지 압축 해제에 실제로 시간이 얼마나 걸리는지 전혀 모릅니다! 제게 JPEG은 즉시 풀리는데, 그건 처리 능력이나 대역폭이 그렇게 제한된 상황을 겪어 본 적이 없어서일 겁니다. 하지만 언젠가 그런 상황에 놓인다면 수치가 있는 편이 차이를 이해하는 데 분명 도움이 될 겁니다.

    몇 년 전에도 비슷한 일이 있었습니다. AWS Athena가 느려서 수백 기가바이트짜리 parquet 파일에 맞는 압축 알고리즘을 골라야 했거든요. zstd의 GitHub에 있는 비교표가 엄청나게 유용했고, 이 분야를 레벨 0에서 레벨 1로 이해하게 해 줬습니다.

    경험 많은 사람에게도 사각지대는 있고, 핵심을 이해하는 데 꼭 필요하다면 뻔한 것도 설명하는 게 좋다고 생각합니다. :)

  16. SwtCyber HN

    게다가 디코딩 시간을 예측할 수 있다는 점도 중요하죠.

  17. rasz HN

    압축 해제 속도를 극단적으로 내세우면서 JPEG과 비교한 수치조차 안 보여 주는 건 의미가 없다

    이건 HDMI 라인 속도로 디코딩합니다. 픽셀당 오피코드 6개로요.

  18. zahlman HN

    "압축"의 정의를 억지로 늘이는 것 같은데요. 델타 코딩 필터에 팔레트화를 얹은 게 전부 아닌가요?

    추가: 이렇게 잘 동작한다는 게 놀랍긴 합니다(멋지기도 하고요). 디코더가 델타 코딩을 되돌려야 하니 오차가 누적될 줄 알았거든요. 플로이드-스타인버그 디더링을 언급한 걸 봤는데, 아마 그걸 위한 것이겠죠. 여러 색 축에서 동시에 제대로 돌아가게 만들기는 어려워 보이지만, 복잡한 부분은 전부 인코더에 있으니까요.

  19. schiffern HN

    플로이드-스타인버그 디더링은 양자화 오차를 이웃 픽셀로 넘겨서 100% 보존합니다(오차의 75%만 보존하는 Atkinson 디더링 등과 다릅니다[0]). 그러니 드리프트가 없다는 게 그리 놀랍지는 않을 것 같아요.

    여러 색 축에 걸친 오차 추적은, 제 단순한 짐작으로는 3차원 벡터(선형화된 지각 색 공간일 수도 있고 RGB일 수도 있고)로 다루고 인코더가 최소화하는 오차 항이 그 벡터의 크기일 것 같은데요?

    아주 멋집니다. '진짜' 영상 포맷이라기보다 임베디드 CPU용 코딩 연습으로 이해하는 게 가장 좋겠지만, 그래도 인상적인 건 마찬가지라고 생각합니다.

    [0] https://beyondloom.com/blog/dither.html

  20. SwtCyber HN

    핵심은 인코더가 디코더가 매 단계에서 무엇을 복원할지 정확히 알고 있다는 점이라고 봅니다. 그래서 다음 팔레트 항목을 고를 때 앞선 오차를 보정할 수 있는 거죠.

  21. vardump HN

    Amiga HAM이 조금 떠오릅니다. 가로로 번지는 무늬도 비슷하고요.

    Amiga의 HAM 그래픽 모드도 일종의 압축 방식이라 할 수 있겠죠. 흔히 "OCS"라고 부르는 초기 Amiga 칩셋에서는 입력 6비트로 12비트(4096색)를 얻었고요.

    나중에 나온 AGA 칩셋에서는 입력 8비트로 262144색을 얻었습니다.

  22. Retr0id HN

    RP2350에 맞춰 성능을 최적화한 것은 (깊은 파이프라인과 넓은 ILP/SIMD를 갖춘) 요즘 데스크톱급 코어에서는 거의 확실히 최적이 아닐 거라는 점은 짚어 둘 만합니다.

  23. raphlinus HN

    맞습니다. 이건 자원이 극히 제한된 장치를 위해 최적화한 것이지 요즘 기계용이 아닙니다. 혼동될 여지가 있다면 README를 손보겠습니다.

  24. Vaushite HN

    임베디드 환경에서 비디오 출력 포트로 곧장 이미지를 디코딩하는 용도라고 꽤 분명하게 밝혔는데요.

  25. wiml HN

    재밌네요. Amiga HAM 비디오 모드가 어렴풋이 떠오릅니다.

  26. Vaushite HN

    옛날 Hold And Modify 발상이 살짝 떠오릅니다. 큰 팔레트 값은 새 색을 불러오는 것과 같고, 작은 값은 HAM처럼 동작하는 거죠.

  27. whitten HN

    인상적입니다. 인코딩 속도와 디코딩 속도가 불균형하다는 점은 특수 목적 하드웨어와 소프트웨어 애플리케이션을 만들 때 유용한 전략으로 보입니다. 쓰기 과정은 훨씬 느려도 되고 읽기는 빨라야 하는, 중앙 데이터 원본을 만드는 경우에 이 접근이 유리할 것 같습니다. 이 핵심 방식을 라디오/신호 방송 과정처럼 수신자는 많고 신뢰할 수 있는 원본은 중앙에 하나인 문제 영역에 쓸 수도 있겠죠. 정보 기반이 천천히 바뀌거나 일괄 처리로 미리 가공되는 경우에도 이 방식을 쓸 수 있다고 상상해 봅니다. 중앙 데이터를 반드시 그래픽 이미지로 디코딩해야 하는 것도 아니고요.

    이 라디오 모델은 품목과 가격 목록을 관리하면서 정기적으로 소매점에 방송해야 하는 중앙 집중식 시스템의 문제 영역에도 들어맞을 것 같습니다.

    아니면 복잡한 데이터 처리 계산을 중앙에서 수행해 두고, 로컬에서 계산할 필요 없이 최종 결과만 필요한 수많은 위성 노드가 쓸 수 있게 하는 공용 캐시 저장소로도 쓸 수 있겠고요.

  28. gnabgib HN

    HN에는 비공개 메시지 기능이 없습니다. 이 댓글과 지난 3개월간 쓰신 댓글이 (AI로) 생성된 것처럼 보이는데, 가이드라인[0]에서 금지하는 일이고 커뮤니티에서도 몹시 싫어합니다. 어디까지나 추측일 뿐이지만요.

    https://news.ycombinator.com/newsguidelines.html

  29. ChrisMarshallNY HN

    Dave는 용감한 친구라서 프로필에 개인 전화번호를 올려 뒀습니다. 그걸로 연락할 수는 있겠지만 저라면 안 할 겁니다. 별로 적절하지 않다고 생각해서요. 댓글은 그 정도면 충분하고 도발적이지도 않았다고 봅니다.

    다만 그 댓글에서 "AI 냄새"가 난다는 데는 저도 동의합니다. 그래도 원래 문체가 그런 거라면 아닐 수도 있죠. 저는 10년 전에 쓴 글로도 "봇"이라는 소리를 들은 적이 있습니다. 제가 보기에 사람들은 길이가 긴 댓글이면 무조건 LLM이 쓴 거라고 의심하는 경향이 있습니다.

  30. whitten HN

    왜 비추천을 받았는지 알고 싶습니다. 배울 수 있게 답글이나 비공개 메시지로 알려 주세요.

Hacker News에서 보기 ↗