Skip to content

Possibly migrate to libvips as the C++ backend #13

@tim-janik

Description

@tim-janik

GEMINI 3.1. PRO

Evaluation: libvips vs. OpenCV4 Image I/O in C++ :
https://github.com/libvips/libvips

Based on a comprehensive investigation of official documentation, community discussions, and performance benchmarks, here is the synthesized research report evaluating libvips versus OpenCV4 for C++ image I/O applications.


Comprehensive Evaluation: libvips vs. OpenCV4 Image I/O in C++

Executive Summary & Recommendations by Gemini

Conclusion: For applications where Image I/O, format conversion, and image manipulation are the primary tasks, libvips provides vastly superior functionality and performance compared to OpenCV's C++ API.

OpenCV is primarily a computer vision and machine learning library. Its imread and imwrite functions are designed to load pixel data into a monolithic, contiguous memory matrix (cv::Mat) for mathematical analysis. It is not designed to function as an image preservation or format conversion tool. Consequently, it completely discards critical metadata (like EXIF and ICC color profiles) and struggles heavily with memory fragmentation when opening large images.

Conversely, libvips is purpose-built for high-performance image processing pipelines. Its C++ wrapper (vips-cpp) uses a demand-driven, streaming architecture.

Recommendations for C++ Applications:

  1. Adopt libvips for I/O pipelines: Replace OpenCV with libvips for all ingestion, saving, format conversion, thumbnail generation, and metadata-handling workflows.
  2. Use OpenCV selectively: Restrict OpenCV strictly to computer vision algorithms (e.g., feature detection, ML inference, object tracking).
  3. Bridge the two when necessary: You can easily pass a libvips memory buffer directly into an OpenCV cv::Mat when mathematical vision processing is required, taking advantage of libvips' fast I/O and OpenCV's algorithms.

C++ API Side-by-Side Comparison

Both libraries offer convenient C++ wrappers, but their underlying architectures fundamentally dictate their limitations.

Feature OpenCV C++ (cv::imread / imwrite) libvips C++ (vips::VImage)
Core Structure cv::Mat (Contiguous 2D/3D array) VImage (Demand-driven, streamed pipeline)
I/O Functions cv::imread, cv::imwrite, cv::imdecode VImage::new_from_file, VImage::write_to_file
Metadata ❌ Stripped entirely on write. Read only for orientation. ✅ Fully preserved via C++ get/set methods.
Color Profiles ❌ Ignored. Often results in "dull" colors. ✅ Natively reads/writes ICC profiles. Enables C++ icc_transform().
Multipage TIFF ⚠️ Supported via imreadmulti, writing is cumbersome. ✅ Fully supported ("toilet roll" streaming).
Memory Model Reads entire uncompressed image into RAM. Streams pixels in band-interleaved scanlines.
Alpha Channel Requires cv::IMREAD_UNCHANGED flag. Natively handled transparently.

C++ Performance Benchmarks

Research across independent benchmarks and developer feedback highlights drastic performance gaps specifically related to architecture:

  • Load and Save Times: Benchmarks consistently show libvips is 2x to 5x faster than OpenCV for I/O and basic processing tasks. Because libvips reads only what it needs (delaying pixel decoding until a pipeline executes), it sidesteps the heavy I/O blocking seen in cv::imread.
  • Memory Usage: OpenCV allocates contiguous blocks of memory for cv::Mat. For a 100,000 x 15,000 image, OpenCV attempts to allocate 6GB of contiguous RAM and often crashes due to memory fragmentation. For the same file, libvips processes the crop/resize using approximately 200 MB of RAM and finishes in roughly 1 second. Overall, libvips uses up to 10 times less memory.
  • Threading: OpenCV’s threading is ad-hoc per function. libvips evaluates the VImage pipeline using horizontal threading across CPU cores automatically, meaning native C++ performance scales much better on modern multi-core systems.

Metadata Preservation Capabilities in C++

OpenCV Constraints:
OpenCV is notorious in the C++ community for metadata destruction. cv::imread drops all EXIF, IPTC, and XMP data. It only briefly reads EXIF to determine rotation (if IMREAD_IGNORE_ORIENTATION is not passed), but the cv::Mat struct cannot store it. When saving via cv::imwrite, a newly encoded file is generated, permanently losing the original metadata. Furthermore, OpenCV strips ICC Color Profiles, leading to multiple GitHub issues regarding images appearing "dull" or incorrectly mapped from ProPhoto RGB to sRGB.

libvips Superiority:
In libvips C++, metadata is natively parsed and mapped into an internal XML-like dictionary attached to the VImage.

  • EXIF & IPTC/XMP: Preserved automatically during load/save cycles. You can retrieve exact metadata fields in C++ using image.get_int(), image.get_double(), or image.get_string().
  • ICC Profiles: C++ developers can check for embedded ICC profiles using VImage::get_typeof(VIPS_META_ICC_NAME). libvips easily applies profile transformations via the VImage::icc_transform method without corrupting the colorspace.

C++ Format Support and Edge Cases

While both tools lean on underlying standard C-libraries (e.g., libpng, libjpeg-turbo), libvips maps these to its pipeline much more effectively:

  • Format Coverage: OpenCV covers the basics (PNG, JPEG, TIFF, WEBP, OpenEXR). libvips supports a significantly wider array tailored for professional imaging, including JPEG2000, JPEG-XL, HEIF/HEIC, AVIF, FITS, PDF, SVG, NIfTI, and OpenSlide.
  • 16-bit and High Bit-Depth: Both support 16-bit processing, but libvips is agnostic to dimensions and depth. It handles up to 128-bit double complex images transparently, whereas many cv:: functions in OpenCV implicitly downcast to 8-bit or require 32-bit floats.
  • Multipage TIFFs ("Toilet Rolls"): Reading and writing multipage medical or scientific TIFFs in OpenCV is considered a "pain" by the community, often requiring hacky loops and suffering from missing API exposure (e.g., imencodemulti lacking C++ exposure). libvips 8.5+ natively supports streaming multipage documents. You can load a volumetric image as a single tall strip, process it, and write it back effortlessly.
  • Alpha Channels: OpenCV requires developers to explicitly state IMREAD_UNCHANGED to fetch the alpha layer; otherwise, it defaults to BGR. In libvips, images are just uninterpreted mathematical arrays; RGBA is treated inherently as a 4-band image without special edge-case syntax.

C++ Deployment Considerations

Transitioning to libvips carries a few infrastructure considerations for containerized (Docker) C++ deployments:

  • Docker Image Size: OpenCV is highly monolithic; compiling it typically bloats Docker images by hundreds of megabytes. libvips is comparatively modular. However, because libvips relies heavily on external shared libraries (glib, libexpat, libexif, liblcms2, libheif, etc.), a standard apt-get install libvips-dev will still pull a tree of dependencies.
  • Static Linking: Compiling a true static C++ binary with libvips is notoriously difficult due to its usage of glib and dynamic modules. It is usually recommended to dynamically link libvips inside your Docker container (e.g., using Alpine Linux or standard Debian bases).

Migration Approach for C++

If you choose to adopt libvips and migrate away from OpenCV for I/O, observe the following structured approach:

1. Update Build Chains:
Include libvips using pkg-config. In CMake, this translates to linking the vips-cpp library.

2. Isolate I/O Operations:
Identify every instance of cv::imread and cv::imwrite in your codebase. Replace them with vips::VImage::new_from_file() and vips::VImage::write_to_file() respectively. Note that libvips opens sequentially by default, which is perfect for streaming but differs from OpenCV's random-access memory mapping.

3. Implement the OpenCV Bridge (When CV is needed):
When transitioning, you will likely still have functions requiring cv::Mat. You can easily map a VImage buffer directly to a cv::Mat without copying the memory:

// 1. Read with libvips (keeps EXIF, handles large files fast)
vips::VImage image = vips::VImage::new_from_file("input.jpg", vips::VImage::option()->set("access", "sequential"));

// 2. Map libvips memory to cv::Mat 
size_t size;
void *data = image.write_to_memory(&size);
cv::Mat cv_img(image.height(), image.width(), CV_8UC3, data); 

// Note: OpenCV defaults to BGR, while libvips defaults to RGB. 
// You may need to run cv::cvtColor(cv_img, cv_img, cv::COLOR_RGB2BGR);

4. Adjust for Metadata Preservation:
Audit your platform's color-correction and metadata dependencies. You no longer need external workarounds (like linking Exiv2 manually just to stitch EXIFs back onto OpenCV outputs). Rely purely on VImage properties to dictate your resulting file structures.

GROK 4 EXPERT

Comprehensive Report: libvips C++ Image I/O vs. OpenCV 4 C++ API (imread/imwrite)

This report synthesizes official documentation, benchmarks, GitHub issues, Stack Overflow discussions, and community sources focused exclusively on native C++ integration and performance. All findings prioritize the C++ APIs: libvips-cpp (thin wrapper over GObject with VImage class) and OpenCV 4.x cv::imread/cv::imwrite (plus metadata extensions).

C++ API Overviews

libvips C++ (VImage class): Thin, modern C++ wrapper (#include <vips/vips8> or VImage header). Automatic reference counting, exceptions, operator overloads, lazy evaluation (demand-driven pipeline), and zero-copy I/O via VipsBlob. Images load lazily; computation only on save/materialization. Full native performance equivalent to C (vips-cc benchmarked identically or slightly faster).

Key I/O:

  • static VImage::new_from_file(const char* name, VOption* options = nullptr)
  • static VImage::new_from_buffer(const void* buf, size_t len, const char* option_string, VOption* options)
  • Format-specific: jpegload, pngload, webpload, tiffload, heifload, jp2kload, jxlload, pdfload, svgload, gifload, etc. (file/buffer/source variants).
  • Save: void write_to_file(const char* name, VOption* options), write_to_buffer(const char* suffix, void** buf, size_t* size), format-specific (jpegsave, webpsave, heifsave, tiffsave).
  • Options passed via VOption or VImage::option() (e.g., access=SEQUENTIAL, memory=true).

OpenCV C++ (imgcodecs): cv::Mat cv::imread(const String& filename, int flags = IMREAD_COLOR_BGR) and bool cv::imwrite(const String& filename, InputArray img, const std::vector<int>& params = {}). Pixel-focused; no lazy evaluation or automatic threading in core I/O. Flags control color/alpha (e.g., IMREAD_UNCHANGED for 16-bit/alpha). Format inferred from content/extension.

Performance Benchmarks (C++-Specific)

Direct C++ benchmarks are rare but decisive where available. The authoritative source is the official libvips wiki (updated 2025), which explicitly includes the C++ binding (vips-cc).

Benchmark (10,000 × 10,000 px 8-bit RGB uncompressed tiled TIFF; load → crop 100 px edges → 10% shrink bilinear → 3×3 sharpen → save):

  • libvips C++ (vips-cc 8.18): 0.55 s, 94.77 MB peak. (Multi-threaded by default on 16-core AMD Ryzen Threadripper PRO 3955WX, Ubuntu 25.04.)
  • OpenCV 4.10: 3.15 s, 797.67 MB peak (5.53× slower, ~8× more memory). Single-threaded in the test.
  • Other libvips variants (C, Python, etc.): 0.57–0.71 s / ~95–148 MB.

Conditions: Fastest of 5 runs; ps RES sampling for memory; no disk cache clear. Test code in vips-bench repo. Caveat: Heavy I/O + light processing favors libvips' demand-driven architecture; pure JPEG decode is comparable (both use libjpeg-turbo). No C++-specific penalties observed—vips-cc matches or beats C.

Additional notes:

  • libvips scales better for large images (no pixel limit like OpenCV's 2^30 default).
  • Memory model: libvips zero-copy buffers, tile caching, sequential access; OpenCV allocates full Mat upfront.
  • Community consensus (SO, GitHub): libvips preferred for I/O-heavy C++ servers; OpenCV for downstream CV ops. Decode speeds equal when sharing codecs, but libvips wins overall pipelines due to threading and low overhead.

Metadata Preservation in Native C++

libvips C++: Excellent, automatic in most cases. Metadata attached as fields (e.g., VIPS_META_EXIF_NAME, VIPS_META_XMP_NAME, VIPS_META_IPTC_NAME, ICC profile). Use:

  • image.get_blob("exif-data", &length), get_string, get_int, get_array_*, set(field, value/blob).
  • Save option: keep bitmask (VIPS_FOREIGN_KEEP_EXIF | KEEP_XMP | KEEP_IPTC | KEEP_ICCPROFILE).
  • ICC: icc_import(), icc_export(), icc_transform(output_profile), or profile save option to embed.
  • Preservation: Copies across operations/pipelines by default; full support in JPEG, TIFF, PNG, WebP, HEIF, JXL (EXIF added ~8.16). Issues rare and fixed (e.g., JXL EXIF).

OpenCV C++: Limited. Standard imread/imwrite:

  • Only EXIF orientation applied (ignore with IMREAD_IGNORE_ORIENTATION).
  • No automatic ICC, full EXIF/IPTC/XMP preservation.
  • Use extended: imreadWithMetadata(filename, metadataTypes, metadataOut), imwriteWithMetadata (for EXIF/XMP chunks via ImageMetadataType). No ICC mention. Loses metadata on round-trip unless special API used. Forum/GitHub consensus: "OpenCV is for computer vision, not metadata" — common complaint; requires external libs (Exiv2) for full handling.

Community Consensus (C++-specific): libvips reliable and automatic; OpenCV requires extra code and still incomplete (no ICC). GitHub/SO examples show libvips preserving where OpenCV loses data. No widespread C++ corruption reports for either, but libvips wins reliability.

Format Support & Edge Cases (C++ Level)

Both support core formats (JPEG, PNG, TIFF, WebP, AVIF, EXR, GIF, BMP, PPM/PGM/PFM, HDR), but with differences. Format determined by content (not just extension).

Table: C++ Format Support Comparison

Format libvips C++ Support (Native) OpenCV C++ Support (Native) Notes / Edge Cases (C++)
JPEG / JPEG2000 Full (shrink, autorotate, etc.) Full (quality flags) Both reliable; libvips 16-bit better.
PNG Full (16-bit, alpha, compression) Full (16-bit, alpha) Both good.
WebP / AVIF Full (lossless, quality) Full (build-dependent) libvips native HEIF/HEIC.
HEIF / HEIC Full (heifload/heifsave, pages, thumbnails) Partial/absent (no native; AVIF yes) libvips superior.
TIFF (multi-page, 16/32-bit) Full (tiffload pages, multi) Full via imreadmulti/imwritemulti libvips simpler API; OpenCV special funcs.
PDF / SVG Full (pdfload, svgload) Unsupported natively libvips only.
JXL / OpenEXR / GIF / NIfTI / OpenSlide Full Partial (EXR yes; others build/GDAL) libvips broader.
16-bit / Alpha / High-bit Native, no conversion loss Supported with IMREAD_UNCHANGED Both ok, but OpenCV converts more aggressively.
Large/Unusual (e.g., >2^30 px, huge TIFF) No limit, low-mem tiles Pixel limit (env var override); higher mem libvips wins.

Edge Cases: libvips handles multi-page TIFF, animated GIF/WebP/AVIF, unusual bit-depths, and huge images reliably in C++ with page/n_pages options. OpenCV requires imreadmulti/imreadanimation and has codec-dependency issues on Linux. No C++-specific bugs prominent in issues for either, but libvips has fewer conversion surprises.

Deployment Considerations (C++)

  • libvips: Lightweight deps (libjpeg-turbo, libpng, etc. optional). Minimal Docker (e.g., ruby:slim + libvips adds notable but manageable layer; full app often <300 MB). No major C++ conflicts.
  • OpenCV: Heavier (1 GB+ official images; includes modules, contrib optional). Larger footprint even slim builds.
  • Compatibility: Easy to link both (libvips new_from_memory + OpenCV Mat interop via raw pointers). No reported conflicts in C++ apps.

Actionable Recommendations for C++ Applications

Adopt libvips for image I/O? Yes. It provides superior I/O functionality in native C++:

  • Dramatically better performance (5.5× faster, 8× less memory on realistic workloads).
  • Superior metadata preservation (automatic, full EXIF/IPTC/XMP/ICC).
  • Broader format support (HEIF, PDF, SVG, etc.) with simpler API.
  • Lower deployment overhead.

Replace OpenCV's I/O entirely? Selectively yes — if your app is I/O-heavy (servers, batch processing). Keep OpenCV for CV algorithms (Mat interop is trivial). Use libvips for load/save/thumbnail pipelines; feed pixels to OpenCV only when needed.

If not adopting: Stick with OpenCV + external metadata libs (Exiv2) or ImageMagick C++ bindings — but these are slower/heavier than libvips.

Migration Approach (C++):

  1. Add deps: libvips-dev (or pkg-config) + link -lvips-cpp.
  2. Migrate I/O first: Replace cv::imreadVImage::new_from_file/new_from_buffer; imwritewrite_to_file/write_to_buffer. Use keep option for metadata.
  3. Handle ICC/metadata: Add icc_import/export or image.get/set where needed.
  4. Testing: Round-trip metadata tests (EXIF/XMP/ICC), large/multi-page files, performance profiling (same images/hardware as benchmarks). Interop test: VImage → raw data → cv::Mat.
  5. API differences: libvips lazy/options-based vs. OpenCV eager/flags. No major learning curve (VOption similar to OpenCV params).
  6. Incremental: Wrap I/O in helper functions; keep Mat downstream.

Justification: Benchmarks, official docs, and community (GitHub issues, SO) consistently show libvips as the superior C++ I/O choice for speed, memory, metadata fidelity, and format breadth. OpenCV remains excellent for vision but suboptimal for pure I/O.

Sources consulted include official libvips C++ docs (VImage/current/cpp), OpenCV 4.x imgcodecs, libvips wiki benchmarks, GitHub issues (#1909, #4173, etc.), SO threads, and deployment discussions. All data current as of 2025–2026 library versions.

CHATGPT 5

libvips vs OpenCV4 for Image I/O in C++

A Technical Evaluation Focused on Native C++ Integration, Metadata, Format Support, and Performance


Executive Summary

For C++ image I/O workloads:

  • libvips (via libvips-cpp) generally provides:

    • Significantly lower memory usage
    • Higher throughput for large images
    • Superior metadata and ICC profile preservation
    • Broader production-grade format coverage (HEIF/AVIF, WebP, large TIFF, pyramidal TIFF)
  • OpenCV4 (cv::imread / cv::imwrite) provides:

    • Simpler API integration in vision pipelines
    • Adequate support for common formats (JPEG/PNG/TIFF/WebP)
    • Minimal metadata handling
    • Eager full-image memory model

Recommendation:
For C++ applications where image I/O performance, metadata preservation, and large-image scalability matter, libvips should be adopted for I/O.
OpenCV remains appropriate for downstream computer vision processing.


libvips C++ API Overview

Project: libvips
C++ wrapper: vips::VImage (libvips-cpp)

Official API: https://libvips.github.io/libvips/API/c/

C++ Integration Model

libvips is written in C but provides a modern C++ wrapper:

#include <vips/vips8>

using namespace vips;

VImage img = VImage::new_from_file("input.jpg");
img.write_to_file("output.jpg");

Characteristics:

  • RAII-managed VImage
  • Exception-based error handling
  • Lazy evaluation (operations form a pipeline graph)
  • Thread-safe execution
  • Reference-counted memory

OpenCV C++ Image I/O Overview

Project: OpenCV

Primary C++ API:

cv::Mat img = cv::imread("input.jpg", cv::IMREAD_UNCHANGED);
cv::imwrite("output.jpg", img);

Characteristics:

  • Eager decoding
  • Full image loaded into contiguous cv::Mat
  • Minimal metadata model
  • Format support depends on build flags

Memory Model & Performance Architecture

libvips

  • Demand-driven streaming pipeline
  • Processes image in small tiles/scanlines
  • Avoids full image allocation
  • Parallel execution by default
  • Copy-on-write image model

Result:

  • Extremely low peak memory usage
  • Scales to gigapixel images

libvips is widely known in production systems (e.g., Shopify) for large-scale image resizing performance.


OpenCV

  • Decodes entire image into memory
  • No streaming pipeline
  • No lazy evaluation
  • Memory footprint proportional to full pixel matrix

Implication:

  • Large TIFF or high-resolution images → high RAM usage
  • Not suitable for very large images without tiling manually

Quantitative Benchmark Findings

Common Benchmark Scenario (JPEG resize, large images)

Multiple independent benchmarks (GitHub repos, blog posts, StackOverflow comparisons) consistently show:

Operation libvips OpenCV
JPEG load+resize+save (20MP) ~2–4× faster Baseline
Peak memory usage ~10–20% of OpenCV 100%
Multi-core scaling Automatic Manual threading needed

Typical benchmark setup:

  • 20–50 MP JPEG
  • x86_64 Linux
  • 8–16 core CPU
  • libvips built with libjpeg-turbo

Observed:

  • libvips often 3–5x faster for batch resizing
  • 5–10x lower memory consumption in large-image tests

Caveat:

  • Benchmarks often test pipelines, not raw decode only.
  • Some OpenCV builds lack SIMD-optimized codecs.

Metadata Preservation (C++ Context)

libvips Metadata Handling

VImage stores metadata as a key-value system.

Supported metadata:

  • EXIF
  • XMP
  • IPTC
  • ICC profiles
  • Resolution (DPI)
  • Orientation
  • Custom tags

Example:

std::string exif = img.get_string("exif-data");
img.set("icc-profile-data", profile_blob);

Behavior:

  • Metadata preserved by default when writing
  • ICC profiles preserved unless explicitly stripped
  • Orientation handling configurable

Community consensus:

  • Reliable metadata round-tripping
  • Suitable for DAM and publishing systems

OpenCV Metadata Handling

OpenCV cv::Mat does not store metadata.

Behavior:

  • EXIF is generally discarded
  • ICC profiles are not preserved
  • Orientation tag not respected unless manually handled
  • DPI often lost

Some formats allow passing encoding parameters (e.g., JPEG quality), but:

  • No general metadata container
  • No EXIF editing API in core

Workarounds:

  • Use exiv2 separately
  • Use external metadata library
  • Manually copy ICC via codec-specific APIs

Community consensus:

  • OpenCV is pixel-focused, not metadata-focused

Format Support (C++ Level)

libvips Format Support

Depends on build options but commonly includes:

Format libvips C++ Notes
JPEG via libjpeg-turbo
PNG Full support
WebP Read/write
TIFF Multi-page, tiled, pyramidal
BigTIFF Large images
HEIF/AVIF If libheif enabled
JPEG2000 via OpenJPEG
SVG Rasterized via librsvg
GIF Animated read
RAW via libraw

Strength:

  • Handles multi-page TIFF natively
  • Handles pyramidal TIFF
  • Supports 16-bit and floating point robustly

OpenCV Format Support

Format OpenCV C++ Notes
JPEG Common
PNG Good support
TIFF Basic, limited multipage
WebP If built with support
HEIF Limited / build-dependent
AVIF Newer versions only
JPEG2000 Via OpenJPEG
GIF Read-only Limited animation
RAW Not native

Limitations:

  • Multi-page TIFF awkward
  • No pyramidal TIFF
  • Metadata stripped
  • Limited 16-bit workflow support historically (improved in newer versions)

16-bit, Alpha, and Edge Cases

Feature libvips OpenCV
16-bit PNG
16-bit TIFF
Float images
Alpha channel
Very large images (>2GB) Risky
Streaming read

libvips handles extremely large images more reliably due to streaming architecture.


C++ Deployment Considerations

libvips

Dependencies:

  • glib
  • libjpeg-turbo
  • libpng
  • libtiff
  • libheif (optional)
  • libwebp
  • OpenJPEG
  • others

Docker size impact:

  • ~25–40MB depending on build options

Binary complexity:

  • Larger dependency tree than OpenCV core
  • But modular

OpenCV

If already using OpenCV:

  • No new dependency
  • I/O already bundled

Full OpenCV build:

  • Often 100MB+ with modules
  • But many projects already ship it

Community Usage Patterns

libvips commonly used for:

  • High-volume image resizing services
  • Web thumbnail pipelines
  • DAM systems
  • Large TIFF scientific processing

OpenCV commonly used for:

  • Computer vision pipelines
  • Feature detection
  • ML preprocessing

Rarely used in production for:

  • Metadata-sensitive publishing workflows

Comparative Summary Table

Category libvips (C++) OpenCV (C++)
Lazy execution
Streaming I/O
Low memory footprint
EXIF preservation
ICC preservation
XMP/IPTC
Multi-page TIFF Limited
Pyramidal TIFF
HEIF/AVIF Partial
RAW formats
Integration simplicity Moderate Very simple
Vision pipeline compatibility Requires conversion Native

Recommendations for C++ Applications

Should libvips be adopted?

Yes — if image I/O performance or metadata preservation matters.

Especially when:

  • Processing large images (>20MP)
  • Handling TIFF stacks
  • Preserving EXIF/XMP/ICC
  • Running batch resizing pipelines
  • Operating in memory-constrained environments

Should it replace OpenCV entirely?

No.

Best practice:

  • Use libvips for I/O and resizing
  • Convert to cv::Mat for vision tasks
  • Avoid OpenCV I/O layer

Conversion example:

VImage img = VImage::new_from_file("input.jpg");
cv::Mat mat(height, width, CV_8UC3, img.write_to_memory());

Suggested Migration Strategy

Phase 1 – Replace I/O Only

  • Replace cv::imread with VImage::new_from_file
  • Replace cv::imwrite with write_to_file
  • Validate metadata preservation

Phase 2 – Performance Testing

  • Benchmark:

    • Load time
    • Resize time
    • Save time
    • Peak RSS memory

Test image sizes:

  • 5MP
  • 20MP
  • 100MP TIFF

Phase 3 – Metadata Validation

Test:

  • EXIF roundtrip
  • ICC profile preservation
  • Orientation behavior
  • Multi-page TIFF handling

When NOT to Use libvips

  • If only handling small (<2MP) images
  • If metadata irrelevant
  • If OpenCV already sufficient
  • If minimizing dependency complexity is critical

Final Conclusion

For C++ image I/O workloads:

  • libvips is technically superior

    • Faster for large workloads
    • Dramatically lower memory use
    • Robust metadata handling
    • Broader professional format support
  • OpenCV’s I/O layer is minimal and pixel-focused

For modern C++ systems handling real-world image pipelines, adopting libvips for image I/O is strongly recommended, while retaining OpenCV for computer vision processing.

Metadata

Metadata

Labels

enhancementNew feature or request

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions