Examples-Sample Applications
🚧 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.
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,
¶ms,
&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:

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.