-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Erode / dilate preliminary implementation. #1744
Changes from all commits
213399f
d7705e3
8d586e1
f8c4a9c
db87b56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -170,6 +170,44 @@ function blur (sigma) { | |
return this; | ||
} | ||
|
||
/** | ||
* Dilate the image. | ||
* @param {Number} [width] dilate width. | ||
* @returns {Sharp} | ||
* @throws {Error} Invalid parameters | ||
*/ | ||
function dilate (width) { | ||
if (!is.defined(width)) { | ||
// No arguments: default to 1px dilation (3x3 mask) | ||
this.options.dilateWidth = 1; | ||
} else if (is.integer(width) && width > 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should place an upper bound on this. Any thoughts on a suitable value? |
||
// Numeric argument: specific width | ||
this.options.dilateWidth = width; | ||
} else { | ||
throw new Error('Invalid dilation width (positive integer) ' + width); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use |
||
} | ||
return this; | ||
} | ||
|
||
/** | ||
* Erode the image. | ||
* @param {Number} [width] erode width. | ||
* @returns {Sharp} | ||
* @throws {Error} Invalid parameters | ||
*/ | ||
function erode (width) { | ||
if (!is.defined(width)) { | ||
// No arguments: default to 1px erosion (3x3 mask) | ||
this.options.erodeWidth = 1; | ||
} else if (is.integer(width) && width > 0) { | ||
// Numeric argument: specific width | ||
this.options.erodeWidth = width; | ||
} else { | ||
throw new Error('Invalid erosion width (positive integer) ' + width); | ||
} | ||
return this; | ||
} | ||
|
||
/** | ||
* Merge alpha transparency channel, if any, with a background. | ||
* @param {Object} [options] | ||
|
@@ -479,6 +517,8 @@ module.exports = function (Sharp) { | |
flip, | ||
flop, | ||
sharpen, | ||
erode, | ||
dilate, | ||
median, | ||
blur, | ||
flatten, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -280,4 +280,28 @@ namespace sharp { | |
return image.linear(a, b); | ||
} | ||
} | ||
|
||
/* | ||
* Dilate an image | ||
*/ | ||
VImage Dilate(VImage image, int const width) { | ||
int maskWidth = 2*width + 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could make this |
||
VImage mask = VImage::new_matrix(maskWidth, maskWidth); | ||
|
||
return image.morph( | ||
mask, | ||
VIPS_OPERATION_MORPHOLOGY_DILATE).invert(); | ||
} | ||
|
||
/* | ||
* Dilate an image | ||
*/ | ||
VImage Erode(VImage image, int const width) { | ||
int maskWidth = 2*width + 1; | ||
VImage mask = VImage::new_matrix(maskWidth, maskWidth); | ||
|
||
return image.morph( | ||
mask, | ||
VIPS_OPERATION_MORPHOLOGY_ERODE).invert(); | ||
} | ||
} // namespace sharp |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -521,6 +521,16 @@ class PipelineWorker : public Nan::AsyncWorker { | |
image = sharp::Threshold(image, baton->threshold, baton->thresholdGrayscale); | ||
} | ||
|
||
// Dilate - must happen before blurring, due to the utility of dilating after thresholding | ||
if (baton->dilateWidth != 0) { | ||
image = sharp::Dilate(image, baton->dilateWidth); | ||
} | ||
|
||
// Erode - must happen before blurring, due to the utility of eroding after thresholding | ||
if (baton->erodeWidth != 0) { | ||
image = sharp::Erode(image, baton->erodeWidth); | ||
} | ||
|
||
// Blur | ||
if (shouldBlur) { | ||
image = sharp::Blur(image, baton->blurSigma); | ||
|
@@ -1271,6 +1281,8 @@ NAN_METHOD(pipeline) { | |
baton->gammaOut = AttrTo<double>(options, "gammaOut"); | ||
baton->linearA = AttrTo<double>(options, "linearA"); | ||
baton->linearB = AttrTo<double>(options, "linearB"); | ||
baton->dilateWidth = AttrTo<int32_t>(options, "dilateWidth"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use unsigned |
||
baton->erodeWidth = AttrTo<int32_t>(options, "erodeWidth"); | ||
baton->greyscale = AttrTo<bool>(options, "greyscale"); | ||
baton->normalise = AttrTo<bool>(options, "normalise"); | ||
baton->useExifOrientation = AttrTo<bool>(options, "useExifOrientation"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use strict'; | ||
|
||
const assert = require('assert'); | ||
|
||
const sharp = require('../../'); | ||
const fixtures = require('../fixtures'); | ||
|
||
describe('Dilate', function () { | ||
it('dilate 1 png', function (done) { | ||
sharp(fixtures.inputPngDotAndLines) | ||
.dilate(1) | ||
.toBuffer(function (err, data, info) { | ||
if (err) throw err; | ||
assert.strictEqual('png', info.format); | ||
assert.strictEqual(100, info.width); | ||
assert.strictEqual(100, info.height); | ||
fixtures.assertSimilar(fixtures.expected('dilate-1.png'), data, done); | ||
}); | ||
}); | ||
|
||
it('dilate 1 png - default width', function (done) { | ||
sharp(fixtures.inputPngDotAndLines) | ||
.dilate() | ||
.toBuffer(function (err, data, info) { | ||
if (err) throw err; | ||
assert.strictEqual('png', info.format); | ||
assert.strictEqual(100, info.width); | ||
assert.strictEqual(100, info.height); | ||
fixtures.assertSimilar(fixtures.expected('dilate-1.png'), data, done); | ||
}); | ||
}); | ||
|
||
it('invalid dilation width', function () { | ||
assert.throws(function () { | ||
sharp(fixtures.inputJpg).dilate(-1); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use strict'; | ||
|
||
const assert = require('assert'); | ||
|
||
const sharp = require('../../'); | ||
const fixtures = require('../fixtures'); | ||
|
||
describe('Erode', function () { | ||
it('erode 1 png', function (done) { | ||
sharp(fixtures.inputPngDotAndLines) | ||
.erode(1) | ||
.toBuffer(function (err, data, info) { | ||
if (err) throw err; | ||
assert.strictEqual('png', info.format); | ||
assert.strictEqual(100, info.width); | ||
assert.strictEqual(100, info.height); | ||
fixtures.assertSimilar(fixtures.expected('erode-1.png'), data, done); | ||
}); | ||
}); | ||
|
||
it('erode 1 png - default width', function (done) { | ||
sharp(fixtures.inputPngDotAndLines) | ||
.erode() | ||
.toBuffer(function (err, data, info) { | ||
if (err) throw err; | ||
assert.strictEqual('png', info.format); | ||
assert.strictEqual(100, info.width); | ||
assert.strictEqual(100, info.height); | ||
fixtures.assertSimilar(fixtures.expected('erode-1.png'), data, done); | ||
}); | ||
}); | ||
|
||
it('invalid erosion width', function () { | ||
assert.throws(function () { | ||
sharp(fixtures.inputJpg).erode(-1); | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be nice to expand a little about what this means and mention things like "morphology" and the use of binary/two-tone/greyscale images being more suitable.