Operator JPEG_Encoder

The operator performs a JPEG compression of grayscale 8-bit images. It uses the JPEG baseline algorithm. The operator's output is a Huffman stream. Optionally, JPEG headers are included in the output (parametrizable). If the headers are included, the output format is JFIF (JPEG File Interchange Format), version 1.2.

The compression rate (and thus the output stream size) depends on two factors:

  • on the selected quantization table which is changeable during runtime.
  • on the input image.

Operator JPEG encoder is able to process the full input data rate as specified in the link parametrization. You can define the throughput rate via the input parallelism. Please note that higher parallelism entails a higher FPGA resource utilization.

The maximum image height is 65.535 pixels. If the image height is not a multiple of eight, the operator internally adds dummy lines. This behaviour reduces the overall input data rate.

The operator allows you to define the quantization table. You have two options to configure the table:

  • The quantization table can be calculated automatically on the basis of a quality value (in percent). For calculation, the standard luminance quantization table (see below) is used. Use parameter Quality (in percent) to configure automatic calculation. Automatic calculation is the default setting of the operator.
  • Alternatively, you can set each of the quantization table values individually. Use parameter LuminanceQuantization to enter your values. Parameter Quality will be automatically disabled in this case by being set to value -1.

The standard luminance quantization table (default setting) looks as follows:

In default mode (automatic calculation out of the standard lumninance quantization table and parameter Quality), the quantization table is calculated by the following equation:

As described above, the operator's output is a Huffman Stream of the encoded image data. For Huffman coding, the standard luminance tables for DC and AC coefficients are used. These tables are fixed and taken from literature, namely W. P. Pennbaker and J. L. Mitchell, 'JPEG Still Image Data Compression Standard', Van Nostrand Rheinhold, 1993. The Huffman Stream generated by the encoder includes the JPEG header if parameter IncludeHeader is set to YES. The generated data stream consists of parallel outputs of multiple bytes (8-bit blocks) where the parallelism is automatically derived from the throughput requirements.

Operator Restrictions

  • The operator does not support empty images, i.e., images with no pixels.

  • Input images with varying line lengths are not allowed.

  • The operator has a minimum input image width which depends on the input parallelism. The minimum input image width is at least twice the input parallelism. The minimum input image width is calculated as follows:

    1. On the basis of the input parallelism: The first multiple of 8 that is equal to or bigger than the input parallelism is identified.
    2. To this multiple of 8, value 1 is added.
    3. On the basis of the result of step 2: As the input image width has to be a multiple of the input parallelism, the first multiple of the input parallelism that is bigger than the result of step 2 is identified.

    The result of step 3 is the minimum input image width for the operator.

    Formula for calculating the minimum input image width

    Figure 407. Formula for calculating the minimum input image width


    For example, if the input parallelism is 4, the minimum input image width is 12.

    If the input parallelism is 12, the minimum input image width is 24.

[Tip] Optimizing the Operator Throughput

If the input parallelism is greater than 8, the data throughput depends on the size of the input image. The maximum data throughput can be achieved with the following image size (OptimalSize):

OptimalSize = Ceil(FrameSize/(PathCount * IntervalSize))*PathCount * IntervalSize
FrameSize = ceil(ImageWidth/8)*8 * ceil(ImageHeight/8)*8;
PathCount = ceil(Par/8)
IntervalSize: Next value greater than 7, which has no common factor with PathCount.

Internally, the operator always uses a parallelism that is a multiple of 8. Depending on the input parallelism, the internal parallelism conversion can compensate some of the loss of bandwidth. The loss of bandwidth only occurs at the end of a frame.

[Note] The End of Image Marker (EOI)

As the size of the compressed image data is not predictable, the last output data byte of a compressed frame might not occur aligned to the output parallelism. Consequently, the last data vector of a frame can contain random dummy values. To mark the actual end of a frame, the EOI (End of Image) marker as defined in the JPEG standard will be used. The EOI marker consists of two bytes. The second last byte of each frame is 0xFF, and the last byte of each frame is 0xD9.

[Tip] Header is output before image data are received

To optimize its image throughput rate (band width), the operator outputs the header as soon as header generation is activated - even before image data arrive at the operator's input. This way, the transfer of the header data doesn't interrupt the transfer of image data, as the header is transferred in advance. The drawback of this practice is that the operator's output transfer starts earlier than the actual image data transfer. This may cause irritations under specific circumstances:

  • Using operator SourceSelector directly after JPEG_Encoder:¬†Operator SourceSelector registers a partly processed frame as soon as it gets the header data. Therefore, if SourceSelector is switched to getting image data from JPEG_Encoder, SourceSelector cannot be switched to any another source as it always detects an unfinished frame. In addition, when header generation is enabled and SourceSelector switches from another source to the JPEG_Encoder channel, the first image is lost.
  • To measure the latency, use operator FrameEndToSignal (instead of FrameStartToSignal and SignalToDelay).
  • If working on eVA devices, please make sure the output is capable to accept data transfer before the sensor transfer is started.

[Tip] Consult the VisualApplets Online Forum!

Get more information and additional examples on VisualApplets' JPEG compression features in the VisualAppletsOnline Community Forum at New High-Speed JPEG Operator and Examples.

I/O Properties

Property Value
Operator Type M
Input Link I, data input
Output Link O, data output

Supported Link Format

Link Parameter Input Link I Output Link O
Bit Width 8 8
Arithmetic unsigned as I
Parallelism any automatically calculated
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

The value must not be lower than the minimum image width requirement.

2

The image width at the output link is configurable. If the output image is bigger than the maximal image width configured for the output link, the image is cut off and the remaining image data is discarded. The last two bytes of each image are always containing the End of Image Marker (EOI).

Parameters

Quality
Type static/dynamic write parameter
Default 50.00
Range [1.00 - 100.00 %], {-1}, step size = 0.01%

Using this parameter, the quality of the JPEG compression can be changed. The quantization matrix is determined from the percentage values using the equation given above. The determined quantization values can be read from parameter quantization_matrix. The parameter is dynamic and should only be changed during idle time of the applet.

Quality settings between 1 and 100 can be defined. Writing to this parameter overwrites manual changes of the quantization matrix made by parameter LuminanceQuantization. If -1 is read from Quality, manual change of the quantization matrix has been made.

The quality parameter is the primary source to define the compression rate of the encoder. The luminance table will be auto-computed from the specified quality and can be read back. However it is possible to modify the luminance table directly. If this happens the quality parameter will be auto-changed to -1 to show that the parameter is not valid anymore and manual overwrite mode for the tables is used. The quality and the quantization tables can be set to static mode if the user wants to optimize resource usage. Static versus dynamic change can be performed only on the quality parameter. The quantization table settings will follow the quality type automatically and cannot be overwritten manually. When the quality is set to static, the operator determines the output parallelism from the quality settings. In most cases the output parallelism will be reduced in comparison to the dynamic mode, which can mean a significant FPGA resource reduction at the cost of giving up the flexibility to change the compression rate during the runtime.

LuminanceQuantization
Type follows Quality type (dynamic or static) write parameter
Default none
Range [1 - 255]

auto computed for quality in range [1.00 - 100.00], when manually set, quality is invalidated to -1.

IncludeHeader
Type static write parameter
Default YES
Range [YES,NO]

The JPEG header is per default included in the compression stream. However, you can disable this feature. If you set parameter IncludeHeader to NO, the JPEG parameters ImageHeight and ImageWidth will become deactivated. If you set parameter IncludeHeader to YES, the header is included and you can decide if the header parameters can be static or are required to be dynamic. If set to static, the values for image width and image height will be statically embedded into the header and cannot be changed, regardless of the input image size. If set to dynamic, you can change the values for image width and image height during the runtime. Please note that these header parameters are not automatically updated to the input image size. If you use the operator with images the size of which is dynamically changing during runtime, you will have to patch the produced header afterwards. If you set ImageHeight and ImageWidth both to "static", you will achieve a slight reduction of the FPGA resource usage.

ImageHeight
Type static/dynamic write parameter
Default 1024
Range 1 - 2^16-1

This parameter is only available if parameter IncludeHeader is set to YES.

Parameter ImageHeight is only used for generating the JPEG image header as described in parameter IncludeHeader.

ImageWidth
Type static/dynamic write parameter
Default 1024
Range 1 - 2^16-1

This parameter is only available if parameter IncludeHeader is set to YES.

Parameter ImageWidth is only used for generating the JPEG image header as described in parameter IncludeHeader.

Examples of Use

The use of operator JPEG_Encoder is shown in the following examples:

More Informations

The following Huffman DC and AC coefficients are used.

      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"
      }
      };