Jump to content

Examples-Sample Applications

From RidgeRun Developer Wiki

Follow us on: YouTube Twitter LinkedIn Email Share this page

Share This Page

🚧 Documentation under development

The PVA ISP for NVIDIA Jetson guide is currently under active development. Some sections may be incomplete or change without notice.

Questions? Contact RidgeRun or email to support@ridgerun.com.

Preferred Partner Logo 3 Partner Program Banner





Sample Applications

The following examples demonstrate how the concepts introduced in Custom Development can be applied to build complete image processing applications.

Complete Example Source Code

The complete source code for the reference application discussed in this page can be found in the online API documentation

Rather than explaining every line of code individually, this page breaks the application into logical blocks and explains the role of each section.

Introduction

The isp_minimal application demonstrates how to:

  • Load a Bayer RAW image.
  • Load ISP parameters from a YAML configuration file.
  • Create a PVA ISP processing pipeline.
  • Configure ISP stages.
  • Execute image processing on the PVA.
  • Save the resulting NV12 image.

Command-Line Interface

The application begins by parsing command-line arguments and storing them in a configuration structure.

struct AppOptions {
  std::string input_path;
  std::string output_path;
  std::string yaml_path;
  std::string graph_path;
  uint32_t image_width = 0;
  uint32_t image_height = 0;
};

The application expects:

  • An input Bayer image.
  • An ISP parameter file.
  • The image resolution.
  • An optional output file path.
  • An optional graph export path.

The command-line parsing logic is implemented in the ParseArgs() function.

Loading ISP Parameters

Once the command-line arguments have been validated, the application loads the ISP configuration from a YAML file.

ISPParams params;
std::string load_error;

if (!LoadISPParams(
        options.yaml_path,
        &params,
        &load_error)) {
  std::cerr
      << "Failed to load ISP params:\n"
      << load_error << "\n";
  return 1;
}

The parameter file contains the configuration values used by the ISP algorithms, including:

  • Decompanding configuration
  • Optical black levels
  • White balance gains
  • Tone mapping parameters
  • Gamma correction values

This allows image tuning without recompiling the application.

Creating the Pipeline

The application creates a Pipeline object that will own and execute the processing graph.

isp::Pipeline pipeline;

isp_example::ConfigurePipelineLogger(
    &pipeline);

The pipeline is responsible for:

  • Managing stages
  • Negotiating frame formats
  • Allocating memory
  • Executing PVA workloads

Creating Frames

Input and output image buffers are represented by Frame objects.

The example creates a Bayer RAW input frame and an NV12 output frame.

auto* frame_bayer_in =
    pipeline->addFrame(
        {options.image_width,
         options.image_height,
         isp::FrameFormat::kBayer,
         isp::FrameDataType::kUInt16,
         options.image_width,
         16,
         resources->bayer_size});

auto* frame_nv12_out =
    pipeline->addFrame(
        {options.image_width,
         options.image_height +
             (options.image_height / 2),
         isp::FrameFormat::kNV12,
         isp::FrameDataType::kUInt8,
         options.image_width,
         8,
         resources->nv12_size});

These frames define the boundaries of the processing graph.

Creating ISP Stages

Each ISP algorithm is instantiated independently and added to the pipeline.

auto* dec =
    pipeline->add(
        isp::createStage(
            isp::StageType::kDecompand));

auto* blc =
    pipeline->add(
        isp::createStage(
            isp::StageType::kBlackLevel));

auto* awb =
    pipeline->add(
        isp::createStage(
            isp::StageType::kWhiteBalance));

auto* dmc =
    pipeline->add(
        isp::createStage(
            isp::StageType::kDemosaic));

auto* global_tm =
    pipeline->add(
        isp::createStage(
            isp::StageType::kGlobalToneMapping));

auto* gamma_tm =
    pipeline->add(
        isp::createStage(
            isp::StageType::kGammaToneMapping));

auto* nv12 =
    pipeline->add(
        isp::createStage(
            isp::StageType::kNV12Conversion));

The example builds a complete ISP pipeline using all currently supported image processing stages.

Configuring ISP Algorithms

After creating the stages, the application configures their properties.

For example, the Decompand stage receives its lookup table configuration:

pipeline->setStageProperty(
    "decompand0",
    "shift_bits",
    static_cast<int64_t>(
        params.decompand.input_shift));

pipeline->setStageProperty(
    "decompand0",
    "x_pts",
    isp::StagePropertyValue{
        params.decompand.x_pts});

pipeline->setStageProperty(
    "decompand0",
    "y_pts",
    isp::StagePropertyValue{
        params.decompand.y_pts});

Similar configuration calls are used to configure:

  • Black Level Correction
  • White Balance
  • Global Tone Mapping
  • Gamma Tone Mapping

The values are loaded from the YAML parameter file and applied before execution.

Connecting the Pipeline

Once all stages have been created and configured, they are connected together to form the final processing graph.

pipeline->link(dec, blc);

pipeline->link(blc, awb);

pipeline->link(awb, dmc);

pipeline->link(
    dmc,
    "scene_key",
    global_tm,
    "scene_key");

pipeline->link(dmc, global_tm);

pipeline->link(global_tm, gamma_tm);

pipeline->link(gamma_tm, nv12);

This creates the following processing flow:

Figure 2. Typical ISP processing pipeline.


Notice that some stages exchange additional control information through auxiliary pads, such as the scene_key connection used by the Global Tone Mapping stage.

Pipeline Initialization

Before execution, the graph must be initialized.

pipeline->init(false);

pipeline->negotiate();

pipeline->allocate();

pipeline->configure();

These steps perform:

  • Graph validation
  • Frame negotiation
  • Memory allocation
  • Stage configuration
  • PVA runtime preparation

After successful initialization, the pipeline is ready for execution.

Loading the Input Image

The example reads the Bayer RAW image from disk and copies it into the pipeline input frame.

std::vector<uint16_t> input;

if (!isp_example::LoadRawImageU16(
        options.input_path,
        resources.bayer_size,
        &input)) {
  return 1;
}

auto* bayer_input =
    reinterpret_cast<uint16_t*>(
        resources.frame_bayer_in->hostPtr);

std::memcpy(
    bayer_input,
    input.data(),
    resources.bayer_size);

At this point the pipeline contains all information required to begin processing.

Executing the Pipeline

The entire ISP graph is executed through a single call.

const uint8_t* output =
    pipeline.process();

This call executes every ISP stage in sequence and returns the processed NV12 image.

The application also measures execution time for performance evaluation.

const auto start =
    std::chrono::steady_clock::now();

const uint8_t* output =
    pipeline.process();

const auto elapsed =
    std::chrono::duration_cast<
        std::chrono::microseconds>(
        std::chrono::steady_clock::now()
            - start)
        .count();

Writing the Output

The resulting NV12 image is written to disk.

return isp_example::WriteBinaryFile(
           options.output_path,
           output,
           resources.nv12_size)
           ? 0
           : 1;

The generated output can then be:

  • Visualized
  • Encoded
  • Streamed
  • Used for AI inference
  • Used for image quality evaluation


After understanding the reference application, developers can:

  • Build custom ISP pipelines.
  • Add or remove ISP stages.
  • Integrate PVA ISP into larger applications.
  • Create application-specific image processing workflows.






Cookies help us deliver our services. By using our services, you agree to our use of cookies.