LERC: An Open Source Library Based on C++ for Raster Data Compression

LERC (Limited Error Raster Compression) is an open-source raster data compression algorithm developed by Esri. It supports fast encoding and decoding of various data types (not just RGB or byte types) while allowing users to set the maximum compression error for each pixel. In simple terms, LERC can achieve efficient compression while precisely controlling data accuracy loss, making it particularly suitable for scenarios with strict accuracy requirements, such as scientific data, geospatial imagery, and elevation models.

🔮 Core Features of LERC

LERC excels in balancing compression ratio and data processing efficiency, with the following key features:

  • Controllable Accuracy: Allows setting the maximum allowable error for each pixel (e.g., 0.1 meters), ensuring data accuracy within the specified range.
  • Data Type Agnostic: Supports various pixel types, including integers and floating-point numbers.
  • Efficient Encoding and Decoding: Extremely fast encoding and decoding speeds, suitable for real-time or large data volume processing.
  • Region Masking: Supports marking which pixels need to be compressed and which should be skipped using BitMask.

⚙️ Quick Start with the Project

To use LERC in your C++ project, you first need to set up the environment.

Installing Dependencies and Compiling the Library

On Ubuntu or similar Linux distributions, you need to install Git and CMake first:

sudo apt-get install git cmake

Next, clone the LERC GitHub repository and compile it:

git clone https://github.com/Esri/lerc.git
cd lerc
mkdir build && cd build
cmake ..
make
sudo make install

This will compile and install the LERC library into the system’s standard library path.

Project Configuration

In your project’s CMakeLists.txt, ensure that the LERC library can be found:

cmake_minimum_required(VERSION 3.10)
project(MyLercProject)

find_package(Lerc REQUIRED)  # Find the installed LERC library

add_executable(my_lerc_app main.cpp)
target_link_libraries(my_lerc_app Lerc::Lerc)  # Link the LERC library

💡 Basic Usage and Code Example

Let’s go through a specific example to understand how to use LERC for data compression and decompression.

Compressing Data

Assuming we have a 2×2 double type raster data block that needs to be compressed:

#include "lerc.h"
#include <vector>
#include <iostream>

int main() {
    // Prepare original data
    std::vector<double> data = {1.0, 2.5, 3.7, 4.9};
    size_t cols = 2;  // Number of columns in the image
    size_t rows = 2;  // Number of rows in the image

    lerc::BitMask bitMask;  // Used to specify valid pixel areas (optional)
    double maxZError = 0.1; // Maximum allowable error, controlling accuracy

    uint8_t* compressedData = nullptr; // Pointer to the compressed data
    size_t compressedSize = 0;         // Size of the compressed data

    // Call LERC for encoding
    int result = lerc_encode_double(data.data(), 
                                    cols, rows, 
                                    maxZError, 
                                    bitMask, 
                                    &compressedData, 
                                    &compressedSize);

    if (result == Lerc_status_code::LERC_OK) {
        std::cout << "Compression successful! Compressed size: " << compressedSize << " bytes" << std::endl;

        // Next, you can perform decompression verification...

    } else {
        std::cerr << "Compression failed, error code: " << result << std::endl;
    }

    // Note: Be sure to free the compressed data at the end
    free(compressedData);
    return 0;
}

Decompressing Data

After successful compression, we can decompress the data for use:

// Assuming compressedData and compressedSize are outputs from the compression step

// Prepare a container for the decompressed data
size_t totalPixels = cols * rows;
std::vector<double> decodedData(totalPixels);

// Call LERC for decoding
int decodeResult = lerc_decode(compressedData, 
                               compressedSize, 
                               cols, rows, 
                               maxZError, 
                               decodedData.data(), 
                               bitMask);

if (decodeResult == Lerc_status_code::LERC_OK) {
    std::cout << "Decompression successful! Data content: ";
    for (const auto& val : decodedData) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
} else {
    std::cerr << "Decompression failed, error code: " << decodeResult << std::endl;
}

🔧 Advanced Application Tips

Once you have mastered the basic usage, these advanced tips can help you better leverage the power of LERC:

  • Select an Appropriate Maximum Error: maxZError is key to balancing compression ratio and accuracy. A smaller value results in higher accuracy but lower compression ratio; a larger value results in higher compression ratio but more detail loss. You need to weigh this based on your data sensitivity and application scenario.
  • Understand the Impact of Data Types: LERC supports multiple data types. For integer data (e.g., elevation values), a smaller maxZError (e.g., 0.001) can be set for nearly lossless compression. For floating-point data (e.g., temperature, elevation), choose maxZError based on measurement accuracy (e.g., 0.1 meters).
  • Utilize BitMask Effectively: lerc::BitMask can mark which pixels are valid. For example, when processing satellite imagery, it can be used to skip cloud-covered or no-data areas, compressing only valid pixels to improve compression efficiency.

🗂️ Main Application Scenarios

The capabilities of LERC are particularly prominent in specific fields:

  • Geographic Information Systems: LERC was originally designed for geospatial raster data, efficiently compressing digital elevation models, satellite imagery, and aerial photographs.
  • Scientific Data Storage: For large-scale floating-point array data in fields such as remote sensing, meteorology, and oceanography, LERC provides high compression ratios with controllable accuracy.
  • Large-Scale Data Processing: LERC supports chunked compression of large raster datasets, facilitating parallel processing and streaming.

⚠️ Practical Considerations

When using LERC in actual projects, please pay attention to the following points:

  • Memory Management: The lerc_encode_* functions internally allocate memory for compressedData, and you must use free(compressedData) after use to prevent memory leaks.
  • Error Handling: Always check the return values of lerc_encode_* and lerc_decode, and perform appropriate error handling based on Lerc_status_code to improve program robustness.
  • Parameter Consistency: During decompression, parameters such as cols and rows must remain consistent with those during compression; otherwise, decompression may fail or result in data errors.

💎 Conclusion

The LERC library provides efficient raster data compression capabilities while allowing users to define the maximum error for each pixel, ensuring data accuracy. It is particularly suitable for handling scientific data and geospatial imagery that require numerical integrity.

Leave a Comment