Switch default interpolator to bicubic #289

Only use gaussian blur for non-linear interpolators

Improves performance of bilinear by ~15%

Add liborc to the packaged build to improve bicubic perf

Add examples of the various interpolation methods

Add bilinear vs bicubic to perf tests
This commit is contained in:
Lovell Fuller
2015-11-15 22:04:31 +00:00
parent 2678d761ba
commit 84fd1caa46
21 changed files with 935 additions and 442 deletions

58
src/operations.cc Executable file → Normal file
View File

@@ -14,11 +14,11 @@ namespace sharp {
// Split src into non-alpha and alpha
VipsImage *srcWithoutAlpha;
if (vips_extract_band(src, &srcWithoutAlpha, 0, "n", src->Bands - 1, NULL))
if (vips_extract_band(src, &srcWithoutAlpha, 0, "n", src->Bands - 1, nullptr))
return -1;
vips_object_local(context, srcWithoutAlpha);
VipsImage *srcAlpha;
if (vips_extract_band(src, &srcAlpha, src->Bands - 1, "n", 1, NULL))
if (vips_extract_band(src, &srcAlpha, src->Bands - 1, "n", 1, nullptr))
return -1;
vips_object_local(context, srcAlpha);
@@ -27,12 +27,12 @@ namespace sharp {
VipsImage *dstAlpha;
if (HasAlpha(dst)) {
// Non-alpha: extract all-but-last channel
if (vips_extract_band(dst, &dstWithoutAlpha, 0, "n", dst->Bands - 1, NULL)) {
if (vips_extract_band(dst, &dstWithoutAlpha, 0, "n", dst->Bands - 1, nullptr)) {
return -1;
}
vips_object_local(context, dstWithoutAlpha);
// Alpha: Extract last channel
if (vips_extract_band(dst, &dstAlpha, dst->Bands - 1, "n", 1, NULL)) {
if (vips_extract_band(dst, &dstAlpha, dst->Bands - 1, "n", 1, nullptr)) {
return -1;
}
vips_object_local(context, dstAlpha);
@@ -41,11 +41,11 @@ namespace sharp {
dstWithoutAlpha = dst;
// Alpha: Use blank, opaque (0xFF) image
VipsImage *black;
if (vips_black(&black, dst->Xsize, dst->Ysize, NULL)) {
if (vips_black(&black, dst->Xsize, dst->Ysize, nullptr)) {
return -1;
}
vips_object_local(context, black);
if (vips_invert(black, &dstAlpha, NULL)) {
if (vips_invert(black, &dstAlpha, nullptr)) {
return -1;
}
vips_object_local(context, dstAlpha);
@@ -53,12 +53,12 @@ namespace sharp {
// Compute normalized input alpha channels:
VipsImage *srcAlphaNormalized;
if (vips_linear1(srcAlpha, &srcAlphaNormalized, 1.0 / 255.0, 0.0, NULL))
if (vips_linear1(srcAlpha, &srcAlphaNormalized, 1.0 / 255.0, 0.0, nullptr))
return -1;
vips_object_local(context, srcAlphaNormalized);
VipsImage *dstAlphaNormalized;
if (vips_linear1(dstAlpha, &dstAlphaNormalized, 1.0 / 255.0, 0.0, NULL))
if (vips_linear1(dstAlpha, &dstAlphaNormalized, 1.0 / 255.0, 0.0, nullptr))
return -1;
vips_object_local(context, dstAlphaNormalized);
@@ -75,17 +75,17 @@ namespace sharp {
// ^^^^^^^^^^^^^^^^^^^
// t1
VipsImage *t0;
if (vips_linear1(srcAlphaNormalized, &t0, -1.0, 1.0, NULL))
if (vips_linear1(srcAlphaNormalized, &t0, -1.0, 1.0, nullptr))
return -1;
vips_object_local(context, t0);
VipsImage *t1;
if (vips_multiply(dstAlphaNormalized, t0, &t1, NULL))
if (vips_multiply(dstAlphaNormalized, t0, &t1, nullptr))
return -1;
vips_object_local(context, t1);
VipsImage *outAlphaNormalized;
if (vips_add(srcAlphaNormalized, t1, &outAlphaNormalized, NULL))
if (vips_add(srcAlphaNormalized, t1, &outAlphaNormalized, nullptr))
return -1;
vips_object_local(context, outAlphaNormalized);
@@ -102,23 +102,23 @@ namespace sharp {
// externally.
//
VipsImage *t2;
if (vips_multiply(dstWithoutAlpha, t0, &t2, NULL))
if (vips_multiply(dstWithoutAlpha, t0, &t2, nullptr))
return -1;
vips_object_local(context, t2);
VipsImage *outRGBPremultiplied;
if (vips_add(srcWithoutAlpha, t2, &outRGBPremultiplied, NULL))
if (vips_add(srcWithoutAlpha, t2, &outRGBPremultiplied, nullptr))
return -1;
vips_object_local(context, outRGBPremultiplied);
// Denormalize output alpha channel:
VipsImage *outAlpha;
if (vips_linear1(outAlphaNormalized, &outAlpha, 255.0, 0.0, NULL))
if (vips_linear1(outAlphaNormalized, &outAlpha, 255.0, 0.0, nullptr))
return -1;
vips_object_local(context, outAlpha);
// Combine RGB and alpha channel into output image:
return vips_bandjoin2(outRGBPremultiplied, outAlpha, out, NULL);
return vips_bandjoin2(outRGBPremultiplied, outAlpha, out, nullptr);
}
/*
@@ -132,25 +132,25 @@ namespace sharp {
}
// Convert to LAB colourspace
VipsImage *lab;
if (vips_colourspace(image, &lab, VIPS_INTERPRETATION_LAB, NULL)) {
if (vips_colourspace(image, &lab, VIPS_INTERPRETATION_LAB, nullptr)) {
return -1;
}
vips_object_local(context, lab);
// Extract luminance
VipsImage *luminance;
if (vips_extract_band(lab, &luminance, 0, "n", 1, NULL)) {
if (vips_extract_band(lab, &luminance, 0, "n", 1, nullptr)) {
return -1;
}
vips_object_local(context, luminance);
// Extract chroma
VipsImage *chroma;
if (vips_extract_band(lab, &chroma, 1, "n", 2, NULL)) {
if (vips_extract_band(lab, &chroma, 1, "n", 2, nullptr)) {
return -1;
}
vips_object_local(context, chroma);
// Find luminance range
VipsImage *stats;
if (vips_stats(luminance, &stats, NULL)) {
if (vips_stats(luminance, &stats, nullptr)) {
return -1;
}
vips_object_local(context, stats);
@@ -161,19 +161,19 @@ namespace sharp {
double a = -(min * f);
// Scale luminance
VipsImage *luminance100;
if (vips_linear1(luminance, &luminance100, f, a, NULL)) {
if (vips_linear1(luminance, &luminance100, f, a, nullptr)) {
return -1;
}
vips_object_local(context, luminance100);
// Join scaled luminance to chroma
VipsImage *normalizedLab;
if (vips_bandjoin2(luminance100, chroma, &normalizedLab, NULL)) {
if (vips_bandjoin2(luminance100, chroma, &normalizedLab, nullptr)) {
return -1;
}
vips_object_local(context, normalizedLab);
// Convert to original colourspace
VipsImage *normalized;
if (vips_colourspace(normalizedLab, &normalized, typeBeforeNormalize, NULL)) {
if (vips_colourspace(normalizedLab, &normalized, typeBeforeNormalize, nullptr)) {
return -1;
}
vips_object_local(context, normalized);
@@ -181,13 +181,13 @@ namespace sharp {
if (HasAlpha(image)) {
// Extract original alpha channel
VipsImage *alpha;
if (vips_extract_band(image, &alpha, image->Bands - 1, "n", 1, NULL)) {
if (vips_extract_band(image, &alpha, image->Bands - 1, "n", 1, nullptr)) {
return -1;
}
vips_object_local(context, alpha);
// Join alpha channel to normalised image
VipsImage *normalizedAlpha;
if (vips_bandjoin2(normalized, alpha, &normalizedAlpha, NULL)) {
if (vips_bandjoin2(normalized, alpha, &normalizedAlpha, nullptr)) {
return -1;
}
vips_object_local(context, normalizedAlpha);
@@ -215,19 +215,19 @@ namespace sharp {
1.0, 1.0, 1.0);
vips_image_set_double(blur, "scale", 9);
vips_object_local(context, blur);
if (vips_conv(image, &blurred, blur, NULL)) {
if (vips_conv(image, &blurred, blur, nullptr)) {
return -1;
}
} else {
// Slower, accurate Gaussian blur
// Create Gaussian function for standard deviation
VipsImage *gaussian;
if (vips_gaussmat(&gaussian, sigma, 0.2, "separable", TRUE, "integer", TRUE, NULL)) {
if (vips_gaussmat(&gaussian, sigma, 0.2, "separable", TRUE, "integer", TRUE, nullptr)) {
return -1;
}
vips_object_local(context, gaussian);
// Apply Gaussian function
if (vips_convsep(image, &blurred, gaussian, "precision", VIPS_PRECISION_INTEGER, NULL)) {
if (vips_convsep(image, &blurred, gaussian, "precision", VIPS_PRECISION_INTEGER, nullptr)) {
return -1;
}
}
@@ -249,12 +249,12 @@ namespace sharp {
-1.0, -1.0, -1.0);
vips_image_set_double(sharpen, "scale", 24);
vips_object_local(context, sharpen);
if (vips_conv(image, &sharpened, sharpen, NULL)) {
if (vips_conv(image, &sharpened, sharpen, nullptr)) {
return -1;
}
} else {
// Slow, accurate sharpen in LAB colour space, with control over flat vs jagged areas
if (vips_sharpen(image, &sharpened, "radius", radius, "m1", flat, "m2", jagged, NULL)) {
if (vips_sharpen(image, &sharpened, "radius", radius, "m1", flat, "m2", jagged, nullptr)) {
return -1;
}
}