Switch from custom trim op to vips_find_trim #914

This commit is contained in:
Lovell Fuller
2018-10-02 11:24:32 +01:00
parent 11900945eb
commit 21fbe546b8
8 changed files with 34 additions and 65 deletions

View File

@@ -324,55 +324,21 @@ namespace sharp {
return image.boolean(imageR, boolean);
}
VImage Trim(VImage image, int const tolerance) {
using sharp::MaximumImageAlpha;
// An equivalent of ImageMagick's -trim in C++ ... automatically remove
// "boring" image edges.
// We use .project to sum the rows and columns of a 0/255 mask image, the first
// non-zero row or column is the object edge. We make the mask image with an
// amount-different-from-background image plus a threshold.
// find the value of the pixel at (0, 0) ... we will search for all pixels
// significantly different from this
std::vector<double> background = image(0, 0);
double const max = MaximumImageAlpha(image.interpretation());
// we need to smooth the image, subtract the background from every pixel, take
// the absolute value of the difference, then threshold
VImage mask = (image.median(3) - background).abs() > (max * tolerance / 100);
// sum mask rows and columns, then search for the first non-zero sum in each
// direction
VImage rows;
VImage columns = mask.project(&rows);
VImage profileLeftV;
VImage profileLeftH = columns.profile(&profileLeftV);
VImage profileRightV;
VImage profileRightH = columns.fliphor().profile(&profileRightV);
VImage profileTopV;
VImage profileTopH = rows.profile(&profileTopV);
VImage profileBottomV;
VImage profileBottomH = rows.flipver().profile(&profileBottomV);
int left = static_cast<int>(floor(profileLeftV.min()));
int right = columns.width() - static_cast<int>(floor(profileRightV.min()));
int top = static_cast<int>(floor(profileTopH.min()));
int bottom = rows.height() - static_cast<int>(floor(profileBottomH.min()));
int width = right - left;
int height = bottom - top;
if (width <= 0 || height <= 0) {
/*
Trim an image
*/
VImage Trim(VImage image, int const threshold) {
// Top-left pixel provides the background colour
VImage background = image.extract_area(0, 0, 1, 1);
if (HasAlpha(background)) {
background = background.flatten();
}
int top, width, height;
int const left = image.find_trim(&top, &width, &height,
VImage::option()->set("background", background(0, 0)));
if (width == 0 || height == 0) {
throw VError("Unexpected error while trimming. Try to lower the tolerance");
}
// and now crop the original image
return image.extract_area(left, top, width, height);
}

View File

@@ -100,7 +100,7 @@ namespace sharp {
/*
Trim an image
*/
VImage Trim(VImage image, int const tolerance);
VImage Trim(VImage image, int const threshold);
/*
* Linear adjustment (a * in + b)

View File

@@ -100,8 +100,8 @@ class PipelineWorker : public Nan::AsyncWorker {
}
// Trim
if (baton->trimTolerance != 0) {
image = sharp::Trim(image, baton->trimTolerance);
if (baton->trimThreshold > 0.0) {
image = sharp::Trim(image, baton->trimThreshold);
}
// Pre extraction
@@ -233,7 +233,7 @@ class PipelineWorker : public Nan::AsyncWorker {
if (
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
(inputImageType == ImageType::JPEG || inputImageType == ImageType::WEBP) &&
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimTolerance == 0
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0
) {
if (xshrink >= 8 * shrink_on_load_factor) {
xfactor = xfactor / 8;
@@ -1183,7 +1183,7 @@ NAN_METHOD(pipeline) {
baton->sharpenJagged = AttrTo<double>(options, "sharpenJagged");
baton->threshold = AttrTo<int32_t>(options, "threshold");
baton->thresholdGrayscale = AttrTo<bool>(options, "thresholdGrayscale");
baton->trimTolerance = AttrTo<int32_t>(options, "trimTolerance");
baton->trimThreshold = AttrTo<double>(options, "trimThreshold");
baton->gamma = AttrTo<double>(options, "gamma");
baton->linearA = AttrTo<double>(options, "linearA");
baton->linearB = AttrTo<double>(options, "linearB");
@@ -1293,7 +1293,7 @@ NAN_METHOD(pipeline) {
}
// Force random access for certain operations
if (baton->accessMethod == VIPS_ACCESS_SEQUENTIAL && (
baton->trimTolerance != 0 || baton->normalise ||
baton->trimThreshold > 0.0 || baton->normalise ||
baton->position == 16 || baton->position == 17)) {
baton->accessMethod = VIPS_ACCESS_RANDOM;
}

View File

@@ -81,7 +81,7 @@ struct PipelineBaton {
double sharpenJagged;
int threshold;
bool thresholdGrayscale;
int trimTolerance;
double trimThreshold;
double linearA;
double linearB;
double gamma;
@@ -176,7 +176,7 @@ struct PipelineBaton {
sharpenJagged(2.0),
threshold(0),
thresholdGrayscale(true),
trimTolerance(0),
trimThreshold(0.0),
linearA(1.0),
linearB(0.0),
gamma(0.0),