mirror of
https://github.com/lovell/sharp.git
synced 2025-12-19 07:15:08 +01:00
Add convolve operation for kernel-based convolution (#479)
This commit is contained in:
committed by
Lovell Fuller
parent
ba5a8b44ed
commit
b70a7d9a3b
@@ -1,5 +1,6 @@
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
@@ -211,6 +212,24 @@ namespace sharp {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convolution with a kernel.
|
||||
*/
|
||||
VImage Convolve(VImage image, int width, int height, double scale, double offset,
|
||||
const std::unique_ptr<double[]> &kernel_v) {
|
||||
VImage kernel = VImage::new_from_memory(
|
||||
kernel_v.get(),
|
||||
width * height * sizeof(double),
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
VIPS_FORMAT_DOUBLE);
|
||||
kernel.set("scale", scale);
|
||||
kernel.set("offset", offset);
|
||||
|
||||
return image.conv(kernel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen.
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define SRC_OPERATIONS_H_
|
||||
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <vips/vips8>
|
||||
|
||||
using vips::VImage;
|
||||
@@ -34,6 +35,12 @@ namespace sharp {
|
||||
*/
|
||||
VImage Blur(VImage image, double const sigma);
|
||||
|
||||
/*
|
||||
* Convolution with a kernel.
|
||||
*/
|
||||
VImage Convolve(VImage image, int width, int height, double scale, double offset,
|
||||
const std::unique_ptr<double[]> &kernel_v);
|
||||
|
||||
/*
|
||||
* Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen.
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
@@ -49,6 +50,7 @@ using sharp::Cutout;
|
||||
using sharp::Normalize;
|
||||
using sharp::Gamma;
|
||||
using sharp::Blur;
|
||||
using sharp::Convolve;
|
||||
using sharp::Sharpen;
|
||||
using sharp::EntropyCrop;
|
||||
using sharp::TileCache;
|
||||
@@ -464,11 +466,12 @@ class PipelineWorker : public AsyncWorker {
|
||||
|
||||
bool shouldAffineTransform = xresidual != 1.0 || yresidual != 1.0;
|
||||
bool shouldBlur = baton->blurSigma != 0.0;
|
||||
bool shouldConv = baton->convKernelWidth * baton->convKernelHeight > 0;
|
||||
bool shouldSharpen = baton->sharpenSigma != 0.0;
|
||||
bool shouldThreshold = baton->threshold != 0;
|
||||
bool shouldCutout = baton->overlayCutout;
|
||||
bool shouldPremultiplyAlpha = HasAlpha(image) &&
|
||||
(shouldAffineTransform || shouldBlur || shouldSharpen || (hasOverlay && !shouldCutout));
|
||||
(shouldAffineTransform || shouldBlur || shouldConv || shouldSharpen || (hasOverlay && !shouldCutout));
|
||||
|
||||
// Premultiply image alpha channel before all transformations to avoid
|
||||
// dark fringing around bright pixels
|
||||
@@ -634,6 +637,14 @@ class PipelineWorker : public AsyncWorker {
|
||||
image = Blur(image, baton->blurSigma);
|
||||
}
|
||||
|
||||
// Convolve
|
||||
if (shouldConv) {
|
||||
image = Convolve(image,
|
||||
baton->convKernelWidth, baton->convKernelHeight,
|
||||
baton->convKernelScale, baton->convKernelOffset,
|
||||
baton->convKernel);
|
||||
}
|
||||
|
||||
// Sharpen
|
||||
if (shouldSharpen) {
|
||||
image = Sharpen(image, baton->sharpenSigma, baton->sharpenFlat, baton->sharpenJagged);
|
||||
@@ -1151,6 +1162,22 @@ NAN_METHOD(pipeline) {
|
||||
} else {
|
||||
baton->tileLayout = VIPS_FOREIGN_DZ_LAYOUT_DZ;
|
||||
}
|
||||
// Convolution Kernel
|
||||
if(Has(options, New("convKernel").ToLocalChecked()).FromJust()) {
|
||||
Local<Object> kernel = Get(options, New("convKernel").ToLocalChecked()).ToLocalChecked().As<Object>();
|
||||
baton->convKernelWidth = attrAs<int32_t>(kernel, "width");
|
||||
baton->convKernelHeight = attrAs<int32_t>(kernel, "height");
|
||||
baton->convKernelScale = attrAs<double>(kernel, "scale");
|
||||
baton->convKernelOffset = attrAs<double>(kernel, "offset");
|
||||
|
||||
size_t kernelSize = baton->convKernelWidth * baton->convKernelHeight;
|
||||
|
||||
baton->convKernel = std::unique_ptr<double[]>(new double[kernelSize]);
|
||||
Local<Array> kdata = Get(kernel, New("kernel").ToLocalChecked()).ToLocalChecked().As<Array>();
|
||||
for(unsigned int i = 0; i < kernelSize; i++) {
|
||||
baton->convKernel[i] = To<double>(Get(kdata, i).ToLocalChecked()).FromJust();
|
||||
}
|
||||
}
|
||||
|
||||
// Function to notify of queue length changes
|
||||
Callback *queueListener = new Callback(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef SRC_PIPELINE_H_
|
||||
#define SRC_PIPELINE_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "nan.h"
|
||||
@@ -83,6 +85,11 @@ struct PipelineBaton {
|
||||
std::string err;
|
||||
bool withMetadata;
|
||||
int withMetadataOrientation;
|
||||
std::unique_ptr<double[]> convKernel;
|
||||
int convKernelWidth;
|
||||
int convKernelHeight;
|
||||
double convKernelScale;
|
||||
double convKernelOffset;
|
||||
int tileSize;
|
||||
int tileOverlap;
|
||||
VipsForeignDzContainer tileContainer;
|
||||
@@ -136,6 +143,10 @@ struct PipelineBaton {
|
||||
optimiseScans(false),
|
||||
withMetadata(false),
|
||||
withMetadataOrientation(-1),
|
||||
convKernelWidth(0),
|
||||
convKernelHeight(0),
|
||||
convKernelScale(0.0),
|
||||
convKernelOffset(0.0),
|
||||
tileSize(256),
|
||||
tileOverlap(0),
|
||||
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
|
||||
|
||||
Reference in New Issue
Block a user