mirror of
https://github.com/lovell/sharp.git
synced 2025-12-19 07:15:08 +01:00
Add most dominant colour to image stats #640
This commit is contained in:
@@ -724,4 +724,25 @@ namespace sharp {
|
||||
return std::make_tuple(image, alphaColour);
|
||||
}
|
||||
|
||||
/*
|
||||
Removes alpha channel, if any.
|
||||
*/
|
||||
VImage RemoveAlpha(VImage image) {
|
||||
if (HasAlpha(image)) {
|
||||
image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
Ensures alpha channel, if missing.
|
||||
*/
|
||||
VImage EnsureAlpha(VImage image) {
|
||||
if (!HasAlpha(image)) {
|
||||
std::vector<double> alpha;
|
||||
alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
|
||||
image = image.bandjoin_const(alpha);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
} // namespace sharp
|
||||
|
||||
10
src/common.h
10
src/common.h
@@ -271,6 +271,16 @@ namespace sharp {
|
||||
*/
|
||||
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour);
|
||||
|
||||
/*
|
||||
Removes alpha channel, if any.
|
||||
*/
|
||||
VImage RemoveAlpha(VImage image);
|
||||
|
||||
/*
|
||||
Ensures alpha channel, if missing.
|
||||
*/
|
||||
VImage EnsureAlpha(VImage image);
|
||||
|
||||
} // namespace sharp
|
||||
|
||||
#endif // SRC_COMMON_H_
|
||||
|
||||
@@ -27,29 +27,6 @@ using vips::VImage;
|
||||
using vips::VError;
|
||||
|
||||
namespace sharp {
|
||||
|
||||
/*
|
||||
Removes alpha channel, if any.
|
||||
*/
|
||||
VImage RemoveAlpha(VImage image) {
|
||||
if (HasAlpha(image)) {
|
||||
image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
Ensures alpha channel, if missing.
|
||||
*/
|
||||
VImage EnsureAlpha(VImage image) {
|
||||
if (!HasAlpha(image)) {
|
||||
std::vector<double> alpha;
|
||||
alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
|
||||
image = image.bandjoin_const(alpha);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tint an image using the specified chroma, preserving the original image luminance
|
||||
*/
|
||||
|
||||
@@ -25,16 +25,6 @@ using vips::VImage;
|
||||
|
||||
namespace sharp {
|
||||
|
||||
/*
|
||||
Removes alpha channel, if any.
|
||||
*/
|
||||
VImage RemoveAlpha(VImage image);
|
||||
|
||||
/*
|
||||
Ensures alpha channel, if missing.
|
||||
*/
|
||||
VImage EnsureAlpha(VImage image);
|
||||
|
||||
/*
|
||||
* Tint an image using the specified chroma, preserving the original image luminance
|
||||
*/
|
||||
|
||||
17
src/stats.cc
17
src/stats.cc
@@ -86,6 +86,18 @@ class StatsWorker : public Napi::AsyncWorker {
|
||||
0.0, 1.0, 0.0);
|
||||
laplacian.set("scale", 9.0);
|
||||
baton->sharpness = greyscale.conv(laplacian).deviate();
|
||||
// Most dominant sRGB colour via 4096-bin 3D histogram
|
||||
vips::VImage hist = sharp::RemoveAlpha(image)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB)
|
||||
.hist_find_ndim(VImage::option()->set("bins", 16));
|
||||
std::complex<double> maxpos = hist.maxpos();
|
||||
int const dx = static_cast<int>(std::real(maxpos));
|
||||
int const dy = static_cast<int>(std::imag(maxpos));
|
||||
std::vector<double> pel = hist(dx, dy);
|
||||
int const dz = std::distance(pel.begin(), std::find(pel.begin(), pel.end(), hist.max()));
|
||||
baton->dominantRed = dx * 16 + 8;
|
||||
baton->dominantGreen = dy * 16 + 8;
|
||||
baton->dominantBlue = dz * 16 + 8;
|
||||
} catch (vips::VError const &err) {
|
||||
(baton->err).append(err.what());
|
||||
}
|
||||
@@ -133,6 +145,11 @@ class StatsWorker : public Napi::AsyncWorker {
|
||||
info.Set("isOpaque", baton->isOpaque);
|
||||
info.Set("entropy", baton->entropy);
|
||||
info.Set("sharpness", baton->sharpness);
|
||||
Napi::Object dominant = Napi::Object::New(env);
|
||||
dominant.Set("r", baton->dominantRed);
|
||||
dominant.Set("g", baton->dominantGreen);
|
||||
dominant.Set("b", baton->dominantBlue);
|
||||
info.Set("dominant", dominant);
|
||||
Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
|
||||
} else {
|
||||
Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
|
||||
|
||||
@@ -48,6 +48,9 @@ struct StatsBaton {
|
||||
bool isOpaque;
|
||||
double entropy;
|
||||
double sharpness;
|
||||
int dominantRed;
|
||||
int dominantGreen;
|
||||
int dominantBlue;
|
||||
|
||||
std::string err;
|
||||
|
||||
@@ -55,7 +58,10 @@ struct StatsBaton {
|
||||
input(nullptr),
|
||||
isOpaque(true),
|
||||
entropy(0.0),
|
||||
sharpness(0.0)
|
||||
sharpness(0.0),
|
||||
dominantRed(0),
|
||||
dominantGreen(0),
|
||||
dominantBlue(0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user