Refactor pipeline to use common 16-bit detection methods

This commit is contained in:
Lovell Fuller 2016-07-11 23:03:45 +01:00
parent d1d6155fd1
commit c42fb97419
4 changed files with 36 additions and 30 deletions

View File

@ -317,23 +317,26 @@ namespace sharp {
return std::make_tuple(left, top); return std::make_tuple(left, top);
} }
/*
Are pixel values in this image 16-bit integer?
*/
bool Is16Bit(VipsInterpretation const interpretation) {
return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16;
}
/* /*
Return the image alpha maximum. Useful for combining alpha bands. scRGB Return the image alpha maximum. Useful for combining alpha bands. scRGB
images are 0 - 1 for image data, but the alpha is 0 - 255. images are 0 - 1 for image data, but the alpha is 0 - 255.
*/ */
int MaximumImageAlpha(VipsInterpretation interpretation) { double MaximumImageAlpha(VipsInterpretation const interpretation) {
if(interpretation == VIPS_INTERPRETATION_RGB16 || return Is16Bit(interpretation) ? 65535.0 : 255.0;
interpretation == VIPS_INTERPRETATION_GREY16) {
return (65535);
} else {
return (255);
}
} }
/* /*
Get VIPS Boolean operatoin type from string Get boolean operation type from string
*/ */
VipsOperationBoolean GetBooleanOperation(std::string opStr) { VipsOperationBoolean GetBooleanOperation(std::string const opStr) {
return static_cast<VipsOperationBoolean>( return static_cast<VipsOperationBoolean>(
vips_enum_from_nick(nullptr, VIPS_TYPE_OPERATION_BOOLEAN, opStr.data()) vips_enum_from_nick(nullptr, VIPS_TYPE_OPERATION_BOOLEAN, opStr.data())
); );

View File

@ -117,17 +117,21 @@ namespace sharp {
std::tuple<int, int> CalculateCrop(int const inWidth, int const inHeight, std::tuple<int, int> CalculateCrop(int const inWidth, int const inHeight,
int const outWidth, int const outHeight, int const x, int const y); int const outWidth, int const outHeight, int const x, int const y);
/*
Are pixel values in this image 16-bit integer?
*/
bool Is16Bit(VipsInterpretation const interpretation);
/* /*
Return the image alpha maximum. Useful for combining alpha bands. scRGB Return the image alpha maximum. Useful for combining alpha bands. scRGB
images are 0 - 1 for image data, but the alpha is 0 - 255. images are 0 - 1 for image data, but the alpha is 0 - 255.
*/ */
int MaximumImageAlpha(VipsInterpretation interpretation); double MaximumImageAlpha(VipsInterpretation const interpretation);
/* /*
Get VIPS Boolean operatoin type from string Get boolean operation type from string
*/ */
VipsOperationBoolean GetBooleanOperation(std::string opStr); VipsOperationBoolean GetBooleanOperation(std::string const opStr);
} // namespace sharp } // namespace sharp

View File

@ -162,8 +162,8 @@ namespace sharp {
// the range of the mask and the image need to match .. one could be // the range of the mask and the image need to match .. one could be
// 16-bit, one 8-bit // 16-bit, one 8-bit
int dstMax = MaximumImageAlpha(dst.interpretation()); double const dstMax = MaximumImageAlpha(dst.interpretation());
int maskMax = MaximumImageAlpha(mask.interpretation()); double const maskMax = MaximumImageAlpha(mask.interpretation());
// combine the new mask and the existing alpha ... there are // combine the new mask and the existing alpha ... there are
// many ways of doing this, mult is the simplest // many ways of doing this, mult is the simplest
@ -419,7 +419,7 @@ namespace sharp {
// significantly different from this // significantly different from this
std::vector<double> background = image(0, 0); std::vector<double> background = image(0, 0);
int max = MaximumImageAlpha(image.interpretation()); double const max = MaximumImageAlpha(image.interpretation());
// we need to smooth the image, subtract the background from every pixel, take // we need to smooth the image, subtract the background from every pixel, take
// the absolute value of the difference, then threshold // the absolute value of the difference, then threshold

View File

@ -78,9 +78,12 @@ using sharp::IsDzZip;
using sharp::IsV; using sharp::IsV;
using sharp::FreeCallback; using sharp::FreeCallback;
using sharp::CalculateCrop; using sharp::CalculateCrop;
using sharp::Is16Bit;
using sharp::MaximumImageAlpha;
using sharp::GetBooleanOperation;
using sharp::counterProcess; using sharp::counterProcess;
using sharp::counterQueue; using sharp::counterQueue;
using sharp::GetBooleanOperation;
class PipelineWorker : public AsyncWorker { class PipelineWorker : public AsyncWorker {
public: public:
@ -409,13 +412,12 @@ class PipelineWorker : public AsyncWorker {
} }
// Calculate maximum alpha value based on input image pixel depth // Calculate maximum alpha value based on input image pixel depth
bool is16Bit = (image.format() == VIPS_FORMAT_USHORT); double const maxAlpha = MaximumImageAlpha(image.interpretation());
double maxAlpha = is16Bit ? 65535.0 : 255.0;
// Flatten image to remove alpha channel // Flatten image to remove alpha channel
if (baton->flatten && HasAlpha(image)) { if (baton->flatten && HasAlpha(image)) {
// Scale up 8-bit values to match 16-bit input image // Scale up 8-bit values to match 16-bit input image
double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0;
// Background colour // Background colour
std::vector<double> background { std::vector<double> background {
baton->background[0] * multiplier, baton->background[0] * multiplier,
@ -471,7 +473,7 @@ class PipelineWorker : public AsyncWorker {
// Ensure image has an alpha channel when there is an overlay // Ensure image has an alpha channel when there is an overlay
bool hasOverlay = baton->overlayBufferInLength > 0 || !baton->overlayFileIn.empty(); bool hasOverlay = baton->overlayBufferInLength > 0 || !baton->overlayFileIn.empty();
if (hasOverlay && !HasAlpha(image)) { if (hasOverlay && !HasAlpha(image)) {
double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0;
image = image.bandjoin( image = image.bandjoin(
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier) VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier)
); );
@ -481,10 +483,7 @@ class PipelineWorker : public AsyncWorker {
bool shouldBlur = baton->blurSigma != 0.0; bool shouldBlur = baton->blurSigma != 0.0;
bool shouldConv = baton->convKernelWidth * baton->convKernelHeight > 0; bool shouldConv = baton->convKernelWidth * baton->convKernelHeight > 0;
bool shouldSharpen = baton->sharpenSigma != 0.0; bool shouldSharpen = baton->sharpenSigma != 0.0;
bool shouldThreshold = baton->threshold != 0;
bool shouldCutout = baton->overlayCutout; bool shouldCutout = baton->overlayCutout;
bool shouldBandbool = baton->bandBoolOp < VIPS_OPERATION_BOOLEAN_LAST &&
baton->bandBoolOp >= VIPS_OPERATION_BOOLEAN_AND;
bool shouldPremultiplyAlpha = HasAlpha(image) && bool shouldPremultiplyAlpha = HasAlpha(image) &&
(shouldAffineTransform || shouldBlur || shouldConv || shouldSharpen || (hasOverlay && !shouldCutout)); (shouldAffineTransform || shouldBlur || shouldConv || shouldSharpen || (hasOverlay && !shouldCutout));
@ -554,7 +553,7 @@ class PipelineWorker : public AsyncWorker {
if (image.width() != baton->width || image.height() != baton->height) { if (image.width() != baton->width || image.height() != baton->height) {
if (baton->canvas == Canvas::EMBED) { if (baton->canvas == Canvas::EMBED) {
// Scale up 8-bit values to match 16-bit input image // Scale up 8-bit values to match 16-bit input image
double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0;
// Create background colour // Create background colour
std::vector<double> background; std::vector<double> background;
if (image.bands() > 2) { if (image.bands() > 2) {
@ -617,7 +616,7 @@ class PipelineWorker : public AsyncWorker {
// Extend edges // Extend edges
if (baton->extendTop > 0 || baton->extendBottom > 0 || baton->extendLeft > 0 || baton->extendRight > 0) { if (baton->extendTop > 0 || baton->extendBottom > 0 || baton->extendLeft > 0 || baton->extendRight > 0) {
// Scale up 8-bit values to match 16-bit input image // Scale up 8-bit values to match 16-bit input image
const double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0;
// Create background colour // Create background colour
std::vector<double> background { std::vector<double> background {
baton->background[0] * multiplier, baton->background[0] * multiplier,
@ -643,7 +642,7 @@ class PipelineWorker : public AsyncWorker {
} }
// Threshold - must happen before blurring, due to the utility of blurring after thresholding // Threshold - must happen before blurring, due to the utility of blurring after thresholding
if (shouldThreshold) { if (baton->threshold != 0) {
image = Threshold(image, baton->threshold, baton->thresholdGrayscale); image = Threshold(image, baton->threshold, baton->thresholdGrayscale);
} }
@ -758,7 +757,7 @@ class PipelineWorker : public AsyncWorker {
if (shouldPremultiplyAlpha) { if (shouldPremultiplyAlpha) {
image = image.unpremultiply(VImage::option()->set("max_alpha", maxAlpha)); image = image.unpremultiply(VImage::option()->set("max_alpha", maxAlpha));
// Cast pixel values to integer // Cast pixel values to integer
if (is16Bit) { if (Is16Bit(image.interpretation())) {
image = image.cast(VIPS_FORMAT_USHORT); image = image.cast(VIPS_FORMAT_USHORT);
} else { } else {
image = image.cast(VIPS_FORMAT_UCHAR); image = image.cast(VIPS_FORMAT_UCHAR);
@ -776,7 +775,7 @@ class PipelineWorker : public AsyncWorker {
} }
// Convert image to sRGB, if not already // Convert image to sRGB, if not already
if (image.interpretation() == VIPS_INTERPRETATION_RGB16) { if (Is16Bit(image.interpretation())) {
image = image.cast(VIPS_FORMAT_USHORT); image = image.cast(VIPS_FORMAT_USHORT);
} }
if (image.interpretation() != VIPS_INTERPRETATION_sRGB) { if (image.interpretation() != VIPS_INTERPRETATION_sRGB) {
@ -828,7 +827,7 @@ class PipelineWorker : public AsyncWorker {
} }
// Apply per-channel Bandbool bitwise operations after all other operations // Apply per-channel Bandbool bitwise operations after all other operations
if (shouldBandbool) { if (baton->bandBoolOp >= VIPS_OPERATION_BOOLEAN_AND && baton->bandBoolOp < VIPS_OPERATION_BOOLEAN_LAST) {
image = Bandbool(image, baton->bandBoolOp); image = Bandbool(image, baton->bandBoolOp);
} }