연산자 JPEG_Encoder

Operator Library: Compression

이 오퍼레이터는 8비트 그레이스케일 이미지에 대해 JPEG 압축을 수행합니다. JPEG 베이스라인 알고리즘을 사용하며, 오퍼레이터의 출력은 허프만 스트림(Huffman stream)입니다. 선택적으로 출력에 JPEG 헤더를 포함할 수 있습니다(매개변수로 설정 가능). 헤더가 포함된 경우 출력 형식은 JFIF(JPEG File Interchange Format) 버전 1.2입니다.

압축률(및 이에 따른 출력 스트림 크기)은 다음 두 가지 요소에 따라 달라집니다.

  • 런타임 중에 변경 가능한 선택된 양자화 테이블

  • 입력 이미지

오퍼레이터 JPEG_Encoder는 링크 매개변수에 지정된 전체 입력 데이터 전송률을 처리할 수 있습니다. 입력 Parallelism을 통해 처리량(Throughput rate)을 정의할 수 있습니다. Parallelism이 높을수록 FPGA 리소스 사용량이 증가합니다.

최대 이미지 높이는 65,535픽셀입니다. 이미지 높이가 8의 배수가 아닌 경우, 오퍼레이터는 내부적으로 더미 라인을 추가합니다. 이 동작으로 인해 전체 입력 데이터 전송률이 감소합니다.

오퍼레이터를 통해 양자화 테이블을 정의할 수 있습니다. 테이블을 구성하는 방법에는 두 가지가 있습니다.

  • 양자화 테이블은 Quality 값(백분율)을 기반으로 자동으로 계산될 수 있습니다. 계산에는 표준 휘도 양자화 테이블(아래 참조)이 사용됩니다. 자동 계산을 구성하려면 Quality 매개변수(백분율)를 사용하십시오. 자동 계산은 오퍼레이터의 기본 설정입니다.

  • 또는 양자화 테이블 값을 각각 개별적으로 설정할 수도 있습니다. 값을 입력하려면 LuminanceQuantization 매개변수를 사용하십시오. 이 경우 Quality 매개변수는 값 -1로 설정되어 자동으로 비활성화됩니다.

표준 휘도 양자화 테이블(기본 설정)은 다음과 같습니다.

기본 모드(Quality 매개변수로 설정된 표준 휘도 양자화 테이블을 기반으로 자동 계산되는 모드)에서는 다음 방정식을 사용하여 양자화 테이블이 계산됩니다.

위에서 설명한 바와 같이, 오퍼레이터의 출력은 인코딩된 이미지 데이터의 허프만 스트림입니다. 허프만 코딩에는 DC 및 AC 계수를 위한 표준 휘도 테이블이 사용됩니다. 이 테이블들은 고정되어 있으며 문헌(W. P. Pennbaker 및 J. L. Mitchell 저, 'JPEG Still Image Data Compression Standard', Van Nostrand Rheinhold, 1993)에 수록된 내용을 사용합니다. 인코더에 의해 생성된 허프만 스트림은 IncludeHeader 매개변수가 YES로 설정된 경우 JPEG 헤더를 포함합니다. 생성된 데이터 스트림은 여러 바이트(8비트 블록)의 병렬 출력으로 구성되며, 여기서 Parallelism은 처리량 요구 사항에 따라 자동으로 도출됩니다.

오퍼레이터 제한 사항

  • 이 오퍼레이터는 빈 이미지(즉, 픽셀이 없는 이미지)를 지원하지 않습니다.

  • 라인 길이가 다른 입력 이미지는 허용되지 않습니다.

  • 오퍼레이터에는 입력 Parallelism에 따라 달라지는 최소 입력 이미지 너비가 있습니다. 최소 입력 이미지 너비는 입력 Parallelism의 최소 2배 이상입니다. 최소 입력 이미지 너비는 다음과 같이 계산됩니다.

    1. 입력 Parallelism을 기반으로 함: 입력 Parallelism보다 크거나 같은 첫 번째 8의 배수를 식별합니다.

    2. 이 8의 배수에 값 1을 더합니다.

    3. 2단계의 결과에 따라: 입력 이미지 너비는 입력 Parallelism의 배수여야 하므로, 2단계의 결과보다 큰 입력 Parallelism의 첫 번째 배수를 식별합니다.

    3단계의 결과가 오퍼레이터의 최소 입력 이미지 너비가 됩니다.

    최소 입력 이미지 너비 계산 공식

    그림 414. 최소 입력 이미지 너비 계산 공식


    예를 들어 입력 Parallelism이 4인 경우 최소 입력 이미지 너비는 12입니다.

    입력 Parallelism이 12인 경우 최소 입력 이미지 너비는 24입니다.

[팁] operator 처리량 최적화

입력 Parallelism이 8보다 큰 경우, 데이터 처리량은 입력 이미지의 크기에 따라 달라집니다. 최대 데이터 처리량은 다음 이미지 크기(OptimalSize)에서 달성할 수 있습니다.

OptimalSize = Ceil(FrameSize/(PathCount * IntervalSize))*PathCount * IntervalSize

FrameSize = ceil(ImageWidth/8)*8 * ceil(ImageHeight/8)*8;

PathCount = ceil(Par/8)

IntervalSize: PathCount와 공약수가 없는 7보다 큰 다음 값입니다.

내부적으로 operator는 항상 8의 배수인 parallelism을 사용합니다. 입력 parallelism에 따라 내부 parallelism 변환을 통해 대역폭 손실의 일부를 보상할 수 있습니다. 대역폭 손실은 프레임의 끝부분에서만 발생합니다.

압축된 이미지 데이터의 크기는 예측할 수 없으므로, 압축된 프레임의 마지막 출력 데이터 바이트가 출력 parallelism에 정렬되지 않을 수 있습니다. 결과적으로 프레임의 마지막 데이터 벡터에는 임의의 더미 값이 포함될 수 있습니다. 프레임의 실제 끝을 표시하기 위해 JPEG 표준에 정의된 EOI(End of Image) 마커가 사용됩니다. EOI 마커는 두 바이트로 구성됩니다. 각 프레임의 끝에서 두 번째 바이트는 0xFF이고 마지막 바이트는 0xD9입니다.

이미지 처리량(대역폭)을 최적화하기 위해, operator는 이미지 데이터가 operator의 입력에 도달하기도 전에 헤더 생성이 활성화되는 즉시 헤더를 출력합니다. 이렇게 하면 헤더가 미리 전송되므로 헤더 데이터 전송이 이미지 데이터 전송을 방해하지 않습니다. 이 방식의 단점은 operator의 출력 전송이 실제 이미지 데이터 전송보다 일찍 시작된다는 점입니다. 이로 인해 특정 상황에서 다음과 같은 문제가 발생할 수 있습니다.

  • JPEG_Encoder 바로 뒤에 SourceSelector operator 사용: SourceSelector operator는 헤더 데이터를 가져오는 즉시 부분적으로 처리된 프레임을 등록합니다. 따라서 SourceSelector가 JPEG_Encoder로부터 이미지 데이터를 가져오도록 전환된 경우, 항상 완료되지 않은 프레임을 감지하므로 다른 소스로 전환할 수 없습니다. 또한 헤더 생성이 활성화된 상태에서 SourceSelector가 다른 소스에서 JPEG_Encoder 채널로 전환될 때 첫 번째 이미지가 손실됩니다.

  • 지연 시간을 측정하려면 (FrameStartToSignal 및 Signal 대신) FrameEndToSignal operator를 사용하세요.

InfiniteSource를 이용한 오버플로 관리

다음 파라미터 블록에서 InfiniteSource 모드에서는 다음과 같은 이유로 이미지가 손실되거나 손상될 수 있습니다. JPEG_Encoder 모듈 또는 후속 모듈이 대역폭을 처리할 수 없습니다. operator가 부분 이미지를 이미 수신한 상태에서 오버플로가 발생하면, 이후의 모든 들어오는 이미지 데이터는 폐기되고 operator 내의 잘린 이미지가 잘려나가 부분적인 출력 이미지로 이어집니다. 프레임 시작 지점에 도달했을 때 operator가 오버플로 상태인 경우, 전체 프레임이 폐기되고 프레임이 손실됩니다. 잘렸거나 손실된 각 프레임에 대해 VA 이벤트가 생성됩니다(TruncatedEvent 및 LostEvent). JPEG_Encoder 이벤트는 각각 2바이트로 구성된 3개의 패킷으로 이루어져 있습니다. 처음 두 개의 VA 이벤트 패킷은 frame-ID를 구성하며, 이는 단순히 JPEG_Encoder 입력에 도달하는 각 프레임의 Counter입니다. frame-ID는 손실되거나 잘린 정확한 프레임을 식별합니다. 세 번째 패킷은 발생한 오류의 유형을 나타냅니다. Bit 0은 프레임이 손실되었는지(Bit0 = 1) 또는 잘렸는지(Bit0 = 0)를 나타냅니다. 세 번째 패킷의 나머지 15비트는 이벤트가 손실된 경우에만 사용되며, 이는 CPU에 비해 이벤트가 너무 빨리 발생할 때만 발생할 수 있습니다. 세 번째 패킷의 Bit1은 손실된 TruncatedEvent 의 발생을 나타내고, 동일한 패킷의 Bit2는 손실된 LostEvent 의 발생을 나타냅니다. 또한, 손실된 LostEvents 에 대해 Bit[15:3]은 손실된 LostEvents 의 수를 보유하는 Counter를 형성합니다. Counter 값이 0이면, 손실-LostEvent-Counter가 오버플로된 것입니다. 잘린 프레임은 JPEG_Encoder 출력 데이터를 생성하지만 손실된 프레임은 그렇지 않으므로, VA 이벤트는 손실된 LostEvents.

오버플로 이벤트 데이터

그림 415. 오버플로 이벤트 데이터


I/O Properties

Property Value
Operator Type M
입력 링크 I, data input
출력 링크 O, data output

지원되는 Link Format

Link Parameter Input Link I Output Link O
Bit Width 8 8
Arithmetic unsigned as I
Parallelism any 자동으로 계산됨
Kernel Columns 1 as I
Kernel Rows 1 as I
Img Protocol VALT_IMAGE2D as I
Color Format VAF_GRAY as I
Color Flavor FL_NONE as I
Max. Img Width 2^16 -1 = 65.5351 any2
Max. Img Height 2^16 -1 = 65.535 1

1

값은 최소 이미지 너비 요구 사항보다 낮아서는 안 됩니다.

2

출력 링크에서의 이미지 너비는 설정 가능합니다. 출력 이미지가 출력 링크에 대해 설정된 최대 이미지 너비보다 큰 경우, 이미지가 잘리고 나머지 이미지 데이터는 삭제됩니다. 각 이미지의 마지막 두 바이트에는 항상 EOI(End of Image Marker)가 포함됩니다.

Parameters

Quality
Type 정적/동적 쓰기 파라미터
Default 50.00
Range [1.00 - 100.00 %], {-1}, 증가 크기 = 0.01%

이 파라미터를 사용하여 JPEG 압축의 Quality를 변경할 수 있습니다. 양자화 매트릭스는 위에 제시된 방정식을 사용하여 백분율 값으로부터 결정됩니다. 결정된 양자화 값은 quantization_matrix 파라미터에서 읽어올 수 있습니다. 이 파라미터는 동적이므로 애플릿의 유휴 시간(idle time)에만 변경해야 합니다.

1에서 100 사이의 Quality 설정을 정의할 수 있습니다. 이 파라미터에 값을 쓰면 LuminanceQuantization 파라미터로 수행된 양자화 매트릭스의 수동 변경 내용이 덮어써집니다. Quality에서 -1을 읽어오는 경우, 양자화 매트릭스가 수동으로 변경되었음을 의미합니다.

Quality 파라미터는 인코더의 압축률을 정의하는 주된 소스입니다. 휘도 테이블은 지정된 Quality를 기반으로 자동 계산되며 다시 읽어올 수 있습니다. 그러나 휘도 테이블을 직접 수정하는 것도 가능합니다. 이 경우 Quality 파라미터는 파라미터가 더 이상 유효하지 않으며 테이블에 대한 수동 덮어쓰기 모드가 사용됨을 나타내기 위해 -1로 자동 변경됩니다. 사용자가 리소스 사용을 최적화하려는 경우 Quality 및 양자화 테이블을 정적 모드로 설정할 수 있습니다. 정적 및 동적 변경은 Quality 파라미터에서만 수행할 수 있습니다. 양자화 테이블 설정은 Quality 유형을 자동으로 따르며 수동으로 덮어쓸 수 없습니다. Quality가 정적으로 설정되면, 오퍼레이터는 Quality 설정으로부터 출력 Parallelism을 결정합니다. 대부분의 경우 출력 Parallelism은 동적 모드에 비해 감소하며, 이는 런타임 중에 압축률을 변경할 수 있는 유연성을 포기하는 대가로 상당한 FPGA 리소스 감소를 의미할 수 있습니다.

LuminanceQuantization
Type Quality 유형(동적 또는 정적)을 따르는 쓰기 파라미터
Default 없음
Range [1 - 255]

[1.00 - 100.00] 범위의 Quality에 대해 자동 계산되며, 수동으로 설정하면 Quality가 무효화되어 -1이 됩니다.

IncludeHeader
Type 정적 쓰기 파라미터
Default YES
Range [YES,NO]

JPEG 헤더는 기본적으로 압축 스트림에 포함됩니다. 그러나 이 기능을 비활성화할 수 있습니다. IncludeHeader 파라미터를 NO로 설정하면 JPEG 파라미터 ImageHeight와 ImageWidth가 비활성화됩니다. IncludeHeader를 YES로 설정하면 헤더가 포함되며, 헤더 파라미터를 정적으로 설정할지 아니면 동적으로 요구할지 결정할 수 있습니다. 정적으로 설정하면 이미지 너비와 높이 값이 헤더에 정적으로 임베디드되며 입력 이미지 크기와 관계없이 변경할 수 없습니다. 동적으로 설정하면 런타임 중에 이미지 너비와 높이 값을 변경할 수 있습니다. 이러한 헤더 파라미터는 입력 이미지 크기에 맞춰 자동으로 업데이트되지 않음에 유의하십시오. 런타임 중에 크기가 동적으로 변경되는 이미지와 함께 오퍼레이터를 사용하는 경우, 생성된 헤더를 나중에 패치해야 합니다. ImageHeight와 ImageWidth를 모두 "static"으로 설정하면 FPGA 리소스 사용량을 약간 줄일 수 있습니다.

ImageWidth
Type 정적/동적 쓰기 파라미터
Default 1024
Range 1 - 2^16-1

이 파라미터는 IncludeHeader 파라미터가 YES로 설정된 경우에만 사용할 수 있습니다.

파라미터 ImageWidth는 IncludeHeader 파라미터에 설명된 대로 JPEG 이미지 헤더를 생성하는 데만 사용됩니다.

ImageHeight
Type 정적/동적 쓰기 파라미터
Default 1024
Range 1 - 2^16-1

이 파라미터는 IncludeHeader 파라미터가 YES로 설정된 경우에만 사용할 수 있습니다.

파라미터 ImageHeight는 IncludeHeader 파라미터에 설명된 대로 JPEG 이미지 헤더를 생성하는 데만 사용됩니다.

InfiniteSource
Type 정적 쓰기 파라미터
Default DISABLED
Range {ENABLED, DISABLED}

이 오퍼레이터는 카메라 오퍼레이터 바로 뒤에 연결할 수 있습니다. 이 경우 InfiniteSource 파라미터를 ENABLED로 설정해야 합니다. 그러면 오퍼레이터가 활성 오버플로 관리를 수행하고 VA 이벤트 시스템을 통해 소프트웨어에 오버플로 조건을 보고합니다. 오버플로는 오퍼레이터 뒤의 싱크가 전송을 중지/일시 중지하거나 입력 이미지 높이가 8 라인의 배수가 아닌 두 가지 상황에서만 발생할 수 있습니다. 후자의 경우, 오퍼레이터는 JPEG 표준에서 요구하는 대로 마지막 행 JPEG 블록을 완성하기 위해 누락된 라인을 패딩해야 합니다.

자세한 내용은 'Infinite Sources / Connecting Cameras'를 참조하십시오.

사용 예

JPEG_Encoder 오퍼레이터의 사용법은 다음 예시에 나와 있습니다.

추가 정보

다음 허프만 DC 및 AC 계수가 사용됩니다.

 typedef char DCHuffTableType[12][17]; // Huffman table for
      luminance DC coefficients DCHuffTableType Lum_DC_HuffmanTable= { "00", "010", "011", "100",
      "101", "110", "1110", "11110", "111110", "1111110", "11111110", "111111110" }; typedef char
      ACHuffTableType[16][11][17]; // Huffman table for luminance AC coefficients ACHuffTableType
      Lum_AC_HuffmanTable= { { //Run == 0 "1010",//EOB "00", "01", "100", "1011", "11010",
      "1111000", "11111000", "1111110110", "1111111110000010", "1111111110000011" }, { //Run == 1
      "1010",//EOB "1100", "11011", "1111001", "111110110", "11111110110", "1111111110000100",
      "1111111110000101", "1111111110000110", "1111111110000111", "1111111110001000" }, { //Run == 2
      "1010",//EOB "11100", "11111001", "1111110111", "111111110100", "1111111110001001",
      "1111111110001010", "1111111110001011", "1111111110001100", "1111111110001101",
      "1111111110001110" }, { //Run == 3 "1010",//EOB "111010", "111110111", "111111110101",
      "1111111110001111", "1111111110010000", "1111111110010001", "1111111110010010",
      "1111111110010011", "1111111110010100", "1111111110010101" }, { //Run == 4 "1010",//EOB
      "111011", "1111111000", "1111111110010110", "1111111110010111", "1111111110011000",
      "1111111110011001", "1111111110011010", "1111111110011011", "1111111110011100",
      "1111111110011101", }, { //Run == 5 "1010",//EOB "1111010", "11111110111", "1111111110011110",
      "1111111110011111", "1111111110100000", "1111111110100001", "1111111110100010",
      "1111111110100011", "1111111110100100", "1111111110100101" }, { //Run == 6 "1010",//EOB
      "1111011", "111111110110", "1111111110100110", "1111111110100111", "1111111110101000",
      "1111111110101001", "1111111110101010", "1111111110101011", "1111111110101100",
      "1111111110101101" }, { //Run == 7 "1010",//EOB "11111010", "111111110111",
      "1111111110101110", "1111111110101111", "1111111110110000", "1111111110110001",
      "1111111110110010", "1111111110110011", "1111111110110100", "1111111110110101", }, { //Run ==
      8 "1010",//EOB "111111000", "111111111000000", "1111111110110110", "1111111110110111",
      "1111111110111000", "1111111110111001", "1111111110111010", "1111111110111011",
      "1111111110111100", "1111111110111101" }, { //Run == 9 "1010",//EOB "111111001",
      "1111111110111110", "1111111110111111", "1111111111000000", "1111111111000001",
      "1111111111000010", "1111111111000011", "1111111111000100", "1111111111000101",
      "1111111111000110" }, { //Run == 0xA "1010",//EOB "111111010", "1111111111000111",
      "1111111111001000", "1111111111001001", "1111111111001010", "1111111111001011",
      "1111111111001100", "1111111111001101", "1111111111001110", "1111111111001111" }, { //Run ==
      0xB "1010",//EOB "1111111001", "1111111111010000", "1111111111010001", "1111111111010010",
      "1111111111010011", "1111111111010100", "1111111111010101", "1111111111010110",
      "1111111111010111", "1111111111011000" }, { //Run == 0xC "1010",//EOB "1111111010",
      "1111111111011001", "1111111111011010", "1111111111011011", "1111111111011100",
      "1111111111011101", "1111111111011110", "1111111111011111", "1111111111100000",
      "1111111111100001" }, { //Run == 0xD "1010",//EOB "11111111000", "1111111111100010",
      "1111111111100011", "1111111111100100", "1111111111100101", "1111111111100110",
      "1111111111100111", "1111111111101000", "1111111111101001", "1111111111101010" }, { //Run ==
      0xE "1010",//EOB "1111111111101011", "1111111111101100", "1111111111101101",
      "1111111111101110", "1111111111101111", "1111111111110000", "1111111111110001",
      "1111111111110010", "1111111111110011", "1111111111110100" }, { //Run == 0xF "11111111001",
      //ZRL "1111111111110101", "1111111111110110", "1111111111110111", "1111111111111000",
      "1111111111111001", "1111111111111010", "1111111111111011", "1111111111111100",
      "1111111111111101", "1111111111111110" } };