Avir
High-quality pro HDR image resizing / scaling C++ library, including a very fast, precise, SIMD Lanczos resizer (header-only C++)
Install / Use
/learn @avaneev/AvirREADME
AVIR - Image Resizing Algorithm (in C++)
Introduction
Me, Aleksey Vaneev, is happy to offer you an open source image resizing / scaling library which has reached a production level of quality, and is ready to be incorporated into any project. This library features routines for both down- and upsizing of 8- and 16-bit, 1 to 4-channel images. Image resizing routines were implemented in a portable, cross-platform, header-only C++ code, and have a high level of optimality. Beside resizing, this library offers a sub-pixel shift operation. Built-in sRGB gamma correction is available.
The resizing algorithm at first produces 2X upsized image (relative to the source image size, or relative to the destination image size if downsizing is performed) and then performs interpolation using a bank of sinc function-based fractional delay filters. At the last stage a correction filter is applied which fixes smoothing introduced at previous steps.
The resizing algorithm was designed to provide the best visual quality. The author even believes this algorithm provides the "ultimate" level of quality (for an orthogonal, non neural-network, resizing) which cannot be increased further: no math exists to provide a better frequency response, better anti-aliasing quality and at the same time having less ringing artifacts: these are 3 elements that define any resizing algorithm's quality; in AVIR practice these elements have a high correlation to each other, so they can be represented by a single parameter (AVIR offers several parameter sets with varying quality). Algorithm's time performance turned out to be very good as well (for the "ultimate" image quality).
An important element utilized by this algorithm is the so called Peaked Cosine window function, which is applied over sinc function in all filters. Please consult the documentation for more details.
Note that since AVIR implements orthogonal resizing, it may exhibit diagonal aliasing artifacts. These artifacts are usually suppressed by EWA or radial filtering techniques. EWA-like technique is not implemented in AVIR, because it requires considerably more computing resources and may produce a blurred image.
As a bonus, a much faster LANCIR image resizing algorithm is also offered as
a part of this library. But the main focus of this documentation is the
original AVIR image resizing algorithm.
AVIR is dedicated to women. Your digital photos can look good at any size!
P.S. Please credit the author of this library in your documentation in the following way: "AVIR image resizing algorithm designed by Aleksey Vaneev".
Affine and Non-Linear Transformations
AVIR does not offer affine and non-linear image transformations "out of the box". Since upsizing is a relatively fast operation in AVIR (required time scales linearly with the output image area), affine and non-linear transformations can be implemented in steps: 4- to 8-times upsizing, transformation via bilinear interpolation, downsizing (linear proportional affine transformations can probably skip the downsizing step). This should not compromise the transformation quality much as bilinear interpolation's problems will mostly reside in spectral area without useful signal, with a maximum of 0.7 dB high-frequency attenuation for 4-times upsizing, and 0.17 dB attenuation for 8-times upsizing. This approach is probably as time efficient as performing a high-quality transform over the input image directly (the only serious drawback is the increased memory requirement). Note that affine transformations that change image proportions should first apply proportion change during upsizing.
Requirements
C++ compiler and system with efficient "float" floating-point (24-bit mantissa) type support. This library can also internally use the "double" and SIMD floating-point types during resizing if needed. This library does not have dependencies beside the standard C library.
Usage Information
The image resizer is represented by the avir::CImageResizer<> class, which
is a single front-end class for the whole library. Basically, you do not need
to use nor understand any other classes beside this class.
The code of the library resides in the "avir" C++ namespace, effectively isolating it from all other code. The code is thread-safe. You need just a single resizer object per running application, at any time, even when resizing images concurrently.
To resize images in your application, simply add 3 lines of code (note that
you may need to change ImageResizer( 8 ) here, to specify your image's true
bit resolution, which may be 10 or even 16):
#include "avir.h"
avir :: CImageResizer<> ImageResizer( 8 );
ImageResizer.resizeImage( InBuf, 640, 480, 0, OutBuf, 1024, 768, 3, 0 );
// multi-threaded operation requires additional coding, see the documentation
AVIR works with header-less "raw" image buffers. If you are not too familiar
with the low-level "packed interleaved" image storage format, the InBuf is
expected to be w*h*c elements in size, where w and h is the width and
the height of the image in pixels, respectively, and c is the number of
color channels in the image. In the example above, the size of the InBuf is
640*480*3=921600 elements. If you are working with 8-bit images, the buffer
and the elements should have the uint8_t* type; if you are working with
16-bit images, they should have the uint16_t* type. Note that when
processing 16-bit images, the value of 16 should be used in resizer's
constructor. AVIR's algorithm does not discern between channel packing order
(RGBA, ARGB, BGRA, etc.), so if the BGRA ordered elements were passed
to it, the result will be also BGRA.
If the graphics library you are using returns a uint32_t* or unsigned int*
pointer to a raw 4-channel packed pixel data, you will need to cast both the
input and output pointers to the uint8_t* (or unsigned char*) type, when
supplying them to the resizing function, and set the ElCountIO to 4.
For low-ringing performance:
avir :: CImageResizer<> ImageResizer( 8, 0, avir :: CImageResizerParamsLR() );
To use the built-in gamma correction, which is disabled by default, an object
of the avir::CImageResizerVars class, with its variable UseSRGBGamma set
to true, should be supplied to the resizeImage() function. Note that, when
enabled, the gamma correction is applied to all channels (including
alpha-channel), by default. To bypass adjustment of alpha-channel,
additionally set the Vars.AlphaIndex to 3 or 0, depending on pixel packing
order.
avir :: CImageResizerVars Vars;
Vars.UseSRGBGamma = true;
Dithering (error-diffusion dither which is perceptually good) can be enabled this way:
typedef avir :: fpclass_def< float, float,
avir :: CImageResizerDithererErrdINL< float > > fpclass_dith;
avir :: CImageResizer< fpclass_dith > ImageResizer( 8 );
The library is able to process images of any bit depth: this includes 8-bit, 16-bit, float and double types. Larger integer and signed integer types are not supported. Supported source and destination image sizes are only limited by the available system memory. Note that the resizing function applies clipping to integer output only; floating-point output will not be clipped to [0; 1] range.
The code of this library was commented in the Doxygen
style. To generate the documentation locally you may run the
doxygen ./other/avirdoxy.txt command from the library's directory. Note that
the code was suitably documented allowing you to make modifications, and to
gain full understanding of the algorithm.
Preliminary tests show that this library (compiled with Intel C++ Compiler 18.2 with AVX2 instructions enabled, without explicit SIMD resizing code) can resize 8-bit RGB 5184x3456 (17.9 Mpixel) 3-channel image down to 1920x1280 (2.5 Mpixel) image in 245 milliseconds, utilizing a single thread, on Intel Core i7-7700K processor-based system without overclocking. This scales down to 74 milliseconds if 8 threads are utilized.
Multi-threaded operation is not provided by this library "out of the box". The multi-threaded (horizontally-threaded) infrastructure is available, but requires additional system-specific interfacing code for engagement.
SIMD Usage Information
This library is capable of using SIMD floating-point types for internal variables. This means that up to 4 color channels can be processed in parallel. Since the default interleaved processing algorithm itself remains non-SIMD, the use of SIMD internal types is not practical for 1- and 2-channel image resizing (due to overhead). SIMD internal type can be used this way:
#include "avir_float4_sse.h"
avir :: CImageResizer< avir :: fpclass_float4 > ImageResizer( 8 );
For 1-channel and 2-channel image resizing when AVX instructions are allowed, it may be reasonable to utilize de-interleaved SIMD processing algorithm. While it gives no performance benefit, if the "float4" SSE processing type is used, it offers some performance boost, if the "float8" AVX processing type is used (given dithering is not performed, or otherwise performance is reduced at the dithering stage since recursive dithering cannot be parallelized). The internal type remains non-SIMD "float". De-interleaved algorithm can be used this way:
#include "avir_float8_avx.h"
avir :: CImageResizer< avir :: fpclass_float8_dil > ImageResizer( 8 );
It's important to note that on the latest processors (i7-7700K and later) the use of the aforementioned SIMD-specific resizing code may not be justifiable, or may be even counter-productive due to many factors: memory bandwidth bottleneck, incre
Related Skills
node-connect
341.8kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
341.8kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.6kCommit, push, and open a PR
