Add greyscale option to threshold operation (#480)

This commit is contained in:
Matt Hirsch 2016-07-03 14:32:07 -04:00 committed by Lovell Fuller
parent 4b98dbb454
commit 85f20c6e1b
8 changed files with 55 additions and 3 deletions

View File

@ -391,12 +391,14 @@ When a `sigma` is provided, performs a slower, more accurate sharpen of the L ch
* `flat`, if present, is a Number representing the level of sharpening to apply to "flat" areas, defaulting to a value of 1.0. * `flat`, if present, is a Number representing the level of sharpening to apply to "flat" areas, defaulting to a value of 1.0.
* `jagged`, if present, is a Number representing the level of sharpening to apply to "jagged" areas, defaulting to a value of 2.0. * `jagged`, if present, is a Number representing the level of sharpening to apply to "jagged" areas, defaulting to a value of 2.0.
#### threshold([threshold]) #### threshold([threshold], [options])
Converts all pixels in the image to greyscale white or black. Any pixel greather-than-or-equal-to the threshold (0..255) will be white. All others will be black. Converts all pixels in the image to greyscale white or black. Any pixel greather-than-or-equal-to the threshold (0..255) will be white. All others will be black.
* `threshold`, if present, is a Number, representing the level above which pixels will be forced to white. * `threshold`, if present, is a Number, representing the level above which pixels will be forced to white.
* `options`, an options object that may contain a boolean `grayscale` or `greyscale`. When `grayscale` is `true`, `threshold` returns a black and white image, and when `false` a color image with each channel thresholded independently. The default is `grayscale: true` when omitted.
#### gamma([gamma]) #### gamma([gamma])
Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma` then increasing the encoding (brighten) post-resize at a factor of `gamma`. Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma` then increasing the encoding (brighten) post-resize at a factor of `gamma`.

View File

@ -85,6 +85,7 @@ var Sharp = function(input, options) {
sharpenFlat: 1, sharpenFlat: 1,
sharpenJagged: 2, sharpenJagged: 2,
threshold: 0, threshold: 0,
thresholdGrayscale: true,
gamma: 0, gamma: 0,
greyscale: false, greyscale: false,
normalize: 0, normalize: 0,
@ -487,7 +488,7 @@ Sharp.prototype.sharpen = function(sigma, flat, jagged) {
return this; return this;
}; };
Sharp.prototype.threshold = function(threshold) { Sharp.prototype.threshold = function(threshold, options) {
if (typeof threshold === 'undefined') { if (typeof threshold === 'undefined') {
this.options.threshold = 128; this.options.threshold = 128;
} else if (typeof threshold === 'boolean') { } else if (typeof threshold === 'boolean') {
@ -497,6 +498,14 @@ Sharp.prototype.threshold = function(threshold) {
} else { } else {
throw new Error('Invalid threshold (0 to 255) ' + threshold); throw new Error('Invalid threshold (0 to 255) ' + threshold);
} }
if(typeof options === 'undefined' ||
options.greyscale === true || options.grayscale === true) {
this.options.thresholdGrayscale = true;
} else {
this.options.thresholdGrayscale = false;
}
return this; return this;
}; };

View File

@ -327,4 +327,11 @@ namespace sharp {
); );
} }
VImage Threshold(VImage image, double const threshold, bool const thresholdGrayscale) {
if(!thresholdGrayscale) {
return image >= threshold;
}
return image.colourspace(VIPS_INTERPRETATION_B_W) >= threshold;
}
} // namespace sharp } // namespace sharp

View File

@ -54,6 +54,11 @@ namespace sharp {
*/ */
VImage TileCache(VImage image, double const factor); VImage TileCache(VImage image, double const factor);
/*
Threshold an image
*/
VImage Threshold(VImage image, double const threshold, bool const thresholdColor);
} // namespace sharp } // namespace sharp
#endif // SRC_OPERATIONS_H_ #endif // SRC_OPERATIONS_H_

View File

@ -52,6 +52,7 @@ using sharp::Blur;
using sharp::Sharpen; using sharp::Sharpen;
using sharp::EntropyCrop; using sharp::EntropyCrop;
using sharp::TileCache; using sharp::TileCache;
using sharp::Threshold;
using sharp::ImageType; using sharp::ImageType;
using sharp::ImageTypeId; using sharp::ImageTypeId;
@ -625,7 +626,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 (shouldThreshold) {
image = image.colourspace(VIPS_INTERPRETATION_B_W) >= baton->threshold; image = Threshold(image, baton->threshold, baton->thresholdGrayscale);
} }
// Blur // Blur
@ -1107,6 +1108,7 @@ NAN_METHOD(pipeline) {
baton->sharpenFlat = attrAs<double>(options, "sharpenFlat"); baton->sharpenFlat = attrAs<double>(options, "sharpenFlat");
baton->sharpenJagged = attrAs<double>(options, "sharpenJagged"); baton->sharpenJagged = attrAs<double>(options, "sharpenJagged");
baton->threshold = attrAs<int32_t>(options, "threshold"); baton->threshold = attrAs<int32_t>(options, "threshold");
baton->thresholdGrayscale = attrAs<bool>(options, "thresholdGrayscale");
baton->gamma = attrAs<double>(options, "gamma"); baton->gamma = attrAs<double>(options, "gamma");
baton->greyscale = attrAs<bool>(options, "greyscale"); baton->greyscale = attrAs<bool>(options, "greyscale");
baton->normalize = attrAs<bool>(options, "normalize"); baton->normalize = attrAs<bool>(options, "normalize");

View File

@ -58,6 +58,7 @@ struct PipelineBaton {
double sharpenFlat; double sharpenFlat;
double sharpenJagged; double sharpenJagged;
int threshold; int threshold;
bool thresholdGrayscale;
double gamma; double gamma;
bool greyscale; bool greyscale;
bool normalize; bool normalize;
@ -113,6 +114,7 @@ struct PipelineBaton {
sharpenFlat(1.0), sharpenFlat(1.0),
sharpenJagged(2.0), sharpenJagged(2.0),
threshold(0), threshold(0),
thresholdGrayscale(true),
gamma(0.0), gamma(0.0),
greyscale(false), greyscale(false),
normalize(false), normalize(false),

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -52,8 +52,21 @@ describe('Threshold', function() {
assert.strictEqual(240, info.height); assert.strictEqual(240, info.height);
fixtures.assertSimilar(fixtures.expected('threshold-128.jpg'), data, done); fixtures.assertSimilar(fixtures.expected('threshold-128.jpg'), data, done);
}); });
});
it('threshold grayscale: true (=128)', function(done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.threshold(128,{'grayscale':true})
.toBuffer(function(err, data, info) {
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
fixtures.assertSimilar(fixtures.expected('threshold-128.jpg'), data, done);
});
}); });
it('threshold default jpeg', function(done) { it('threshold default jpeg', function(done) {
sharp(fixtures.inputJpg) sharp(fixtures.inputJpg)
.resize(320, 240) .resize(320, 240)
@ -101,6 +114,18 @@ describe('Threshold', function() {
}); });
} }
it('color threshold', function(done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.threshold(128,{'grayscale':false})
.toBuffer(function(err, data, info) {
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
fixtures.assertSimilar(fixtures.expected('threshold-color-128.jpg'), data, done);
});
});
it('invalid threshold -1', function() { it('invalid threshold -1', function() {
assert.throws(function() { assert.throws(function() {
sharp(fixtures.inputJpg).threshold(-1); sharp(fixtures.inputJpg).threshold(-1);