mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 02:18:50 +01:00
Group platform independent c++ code
This commit is contained in:
parent
d338d42a75
commit
bca748ded3
30 changed files with 631 additions and 449 deletions
|
@ -33,18 +33,24 @@ add_library( # Sets the name of the library.
|
|||
SHARED
|
||||
|
||||
# Provides a relative path to your source file(s).
|
||||
core/filter/brightness.cpp
|
||||
core/filter/color_levels.cpp
|
||||
core/filter/contrast.cpp
|
||||
core/filter/curve.cpp
|
||||
core/filter/hslhsv.cpp
|
||||
core/filter/saturation.cpp
|
||||
core/filter/tint.cpp
|
||||
core/filter/warmth.cpp
|
||||
core/filter/yuv.cpp
|
||||
core/lib/spline/spline.cpp
|
||||
filter/brightness.cpp
|
||||
filter/color_levels.cpp
|
||||
filter/contrast.cpp
|
||||
filter/crop.cpp
|
||||
filter/curve.cpp
|
||||
filter/hslhsv.cpp
|
||||
filter/orientation.cpp
|
||||
filter/saturation.cpp
|
||||
filter/tint.cpp
|
||||
filter/warmth.cpp
|
||||
filter/yuv.cpp
|
||||
lib/spline/spline.cpp
|
||||
arbitrary_style_transfer.cpp
|
||||
deep_lap_3.cpp
|
||||
esrgan.cpp
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
#include "exception.h"
|
||||
#include "lib/base_resample.h"
|
||||
#include "log.h"
|
||||
#include "stopwatch.h"
|
||||
#include "tflite_wrapper.h"
|
||||
#include "util.h"
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#include <cassert>
|
||||
|
@ -14,6 +8,13 @@
|
|||
#include <tensorflow/lite/c/c_api.h>
|
||||
#include <vector>
|
||||
|
||||
#include "core/lib/base_resample.h"
|
||||
#include "exception.h"
|
||||
#include "log.h"
|
||||
#include "stopwatch.h"
|
||||
#include "tflite_wrapper.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
using namespace tflite;
|
||||
|
|
61
plugin/android/src/main/cpp/core/filter/brightness.cpp
Normal file
61
plugin/android/src/main/cpp/core/filter/brightness.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "hslhsv.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Brightness {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static constexpr const char *TAG = "Brightness";
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
vector<uint8_t> applyBrightness(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
return Brightness().apply(rgba8, width, height, weight);
|
||||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace core
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Brightness::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const float mul = 1 + weight / 2;
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
auto hsv = filter::rgb8ToHsv(rgba8 + p);
|
||||
hsv[2] = clamp(0.f, hsv[2] * mul, 1.f);
|
||||
const auto &newRgb = filter::hsvToRgb8(hsv.data());
|
||||
memcpy(output.data() + p, newRgb.data(), 3);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace
|
144
plugin/android/src/main/cpp/core/filter/color_levels.cpp
Normal file
144
plugin/android/src/main/cpp/core/filter/color_levels.cpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float INPUT_AMPLITUDE = .4f;
|
||||
constexpr uint8_t OUTPUT_AMPLITUDE = 100;
|
||||
|
||||
class WhitePoint {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static uint8_t applyInputLevel(const uint8_t p, const float weight) {
|
||||
const auto pf = p / 255.f;
|
||||
const auto max = 1 - weight * INPUT_AMPLITUDE;
|
||||
return clamp<int>(0, clamp(0.f, pf, max) / max * 255.f, 255);
|
||||
}
|
||||
|
||||
static uint8_t applyOutputLevel(const uint8_t p, const float weight) {
|
||||
return clamp<int>(0, p / 255.f * (255 - weight * OUTPUT_AMPLITUDE), 255);
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> buildLut(const float weight);
|
||||
|
||||
static constexpr const char *TAG = "WhitePoint";
|
||||
};
|
||||
|
||||
class BlackPoint {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static inline uint8_t applyInputLevel(const uint8_t p, const float weight) {
|
||||
const auto pf = p / 255.f;
|
||||
const auto min = weight * INPUT_AMPLITUDE;
|
||||
return clamp<int>(0, (clamp(min, pf, 1.f) - min) / (1 - min) * 255.f, 255);
|
||||
}
|
||||
|
||||
static inline uint8_t applyOutputLevel(const uint8_t p, const float weight) {
|
||||
const auto x = weight * OUTPUT_AMPLITUDE;
|
||||
return clamp<int>(0, p / 255.f * (255 - x) + x, 255);
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> buildLut(const float weight);
|
||||
|
||||
static constexpr const char *TAG = "BlackPoint";
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
vector<uint8_t> applyWhitePoint(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
return WhitePoint().apply(rgba8, width, height, weight);
|
||||
}
|
||||
|
||||
vector<uint8_t> applyBlackPoint(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
return BlackPoint().apply(rgba8, width, height, weight);
|
||||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace core
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> WhitePoint::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const auto lut = buildLut(weight);
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = lut[rgba8[p + 0]];
|
||||
output[p + 1] = lut[rgba8[p + 1]];
|
||||
output[p + 2] = lut[rgba8[p + 2]];
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<uint8_t> WhitePoint::buildLut(const float weight) {
|
||||
vector<uint8_t> product(256);
|
||||
const float weightAbs = std::abs(weight);
|
||||
const auto fn =
|
||||
weight > 0 ? &WhitePoint::applyInputLevel : &WhitePoint::applyOutputLevel;
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
product[i] = fn(i, weightAbs);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
vector<uint8_t> BlackPoint::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const auto lut = buildLut(weight);
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = lut[rgba8[p + 0]];
|
||||
output[p + 1] = lut[rgba8[p + 1]];
|
||||
output[p + 2] = lut[rgba8[p + 2]];
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<uint8_t> BlackPoint::buildLut(const float weight) {
|
||||
vector<uint8_t> product(256);
|
||||
const float weightAbs = std::abs(weight);
|
||||
const auto fn =
|
||||
weight > 0 ? &BlackPoint::applyInputLevel : &BlackPoint::applyOutputLevel;
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
product[i] = fn(i, weightAbs);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
} // namespace
|
77
plugin/android/src/main/cpp/core/filter/contrast.cpp
Normal file
77
plugin/android/src/main/cpp/core/filter/contrast.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "hslhsv.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Contrast {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static constexpr const char *TAG = "Contrast";
|
||||
};
|
||||
|
||||
inline uint8_t applySingle(const uint8_t p, const float mul) {
|
||||
return clamp(0, static_cast<int>((p - 127) * mul + 127), 0xFF);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> buildLut(const float mul);
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
vector<uint8_t> applyContrast(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
return Contrast().apply(rgba8, width, height, weight);
|
||||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace core
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Contrast::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const float mul = weight >= 0 ? weight + 1 : (weight + 1) * .4f + .6f;
|
||||
const auto lut = buildLut(mul);
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = lut[rgba8[p + 0]];
|
||||
output[p + 1] = lut[rgba8[p + 1]];
|
||||
output[p + 2] = lut[rgba8[p + 2]];
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<uint8_t> buildLut(const float mul) {
|
||||
vector<uint8_t> product(256);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
product[i] = applySingle(i, mul);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -3,7 +3,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "../lib/spline/spline.h"
|
||||
#include "./curve.h"
|
||||
#include "curve.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -11,23 +11,23 @@ namespace {
|
|||
|
||||
std::vector<uint8_t> buildLut(const vector<uint8_t> &from,
|
||||
const vector<uint8_t> &to);
|
||||
vector<double> transformPoints(const vector<uint8_t> &pts);
|
||||
std::vector<double> transformPoints(const vector<uint8_t> &pts);
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace plugin {
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
Curve::Curve(const vector<uint8_t> &from, const vector<uint8_t> &to)
|
||||
: lut(buildLut(from, to)) {}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace plugin
|
||||
} // namespace core
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<uint8_t> buildLut(const vector<uint8_t> &from,
|
||||
const vector<uint8_t> &to) {
|
||||
vector<uint8_t> buildLut(const vector<uint8_t> &from,
|
||||
const vector<uint8_t> &to) {
|
||||
assert(from.size() >= 2);
|
||||
assert(from[0] == 0);
|
||||
assert(from[from.size() - 1] == 255);
|
||||
|
@ -36,7 +36,7 @@ std::vector<uint8_t> buildLut(const vector<uint8_t> &from,
|
|||
assert(to[to.size() - 1] == 255);
|
||||
tk::spline spline(transformPoints(from), transformPoints(to),
|
||||
tk::spline::cspline_hermite);
|
||||
std::vector<uint8_t> lut;
|
||||
vector<uint8_t> lut;
|
||||
lut.reserve(256);
|
||||
for (int i = 0; i <= 0xFF; ++i) {
|
||||
lut.push_back(std::min(std::max(0, static_cast<int>(spline(i))), 0xFF));
|
|
@ -1,7 +1,7 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace plugin {
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
class Curve {
|
||||
|
@ -23,4 +23,4 @@ private:
|
|||
};
|
||||
|
||||
} // namespace filter
|
||||
} // namespace plugin
|
||||
} // namespace core
|
30
plugin/android/src/main/cpp/core/filter/filters.h
Normal file
30
plugin/android/src/main/cpp/core/filter/filters.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
std::vector<uint8_t> applyBrightness(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
std::vector<uint8_t> applyWhitePoint(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
std::vector<uint8_t> applyBlackPoint(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
std::vector<uint8_t> applyContrast(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
std::vector<uint8_t> applySaturation(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
std::vector<uint8_t> applyTint(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
std::vector<uint8_t> applyWarmth(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
} // namespace filter
|
||||
} // namespace core
|
|
@ -4,11 +4,11 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "../math_util.h"
|
||||
#include "./hslhsv.h"
|
||||
#include "hslhsv.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace plugin {
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
array<float, 3> rgb8ToHsl(const uint8_t *rgb8) {
|
||||
|
@ -167,4 +167,4 @@ std::array<float, 3> hsvToHsl(const float *hsv) {
|
|||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace plugin
|
||||
} // namespace core
|
|
@ -3,7 +3,7 @@
|
|||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace plugin {
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
std::array<float, 3> rgb8ToHsl(const uint8_t *rgb8);
|
||||
|
@ -16,4 +16,4 @@ std::array<float, 3> hslToHsv(const float *hsl);
|
|||
std::array<float, 3> hsvToHsl(const float *hsv);
|
||||
|
||||
} // namespace filter
|
||||
} // namespace plugin
|
||||
} // namespace core
|
44
plugin/android/src/main/cpp/core/filter/saturation.cpp
Normal file
44
plugin/android/src/main/cpp/core/filter/saturation.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "hslhsv.h"
|
||||
#include "saturation.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
vector<uint8_t> applySaturation(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
return Saturation().apply(rgba8, width, height, weight);
|
||||
}
|
||||
|
||||
vector<uint8_t> Saturation::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
auto hsl = filter::rgb8ToHsl(rgba8 + p);
|
||||
hsl[1] = clamp(0.f, hsl[1] * (1 + weight), 1.f);
|
||||
const auto &newRgb = filter::hslToRgb8(hsl.data());
|
||||
memcpy(output.data() + p, newRgb.data(), 3);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace core
|
|
@ -1,7 +1,7 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace plugin {
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
class Saturation {
|
||||
|
@ -14,4 +14,4 @@ private:
|
|||
};
|
||||
|
||||
} // namespace filter
|
||||
} // namespace plugin
|
||||
} // namespace core
|
62
plugin/android/src/main/cpp/core/filter/tint.cpp
Normal file
62
plugin/android/src/main/cpp/core/filter/tint.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "yuv.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Tint {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static constexpr const char *TAG = "Tint";
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
vector<uint8_t> applyTint(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
return Tint().apply(rgba8, width, height, weight);
|
||||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace core
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Tint::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
auto yuv = filter::rgb8ToYuv(rgba8 + p);
|
||||
// +-0.1
|
||||
yuv[1] = clamp(0.f, yuv[1] + 0.1f * weight, 1.f);
|
||||
yuv[2] = clamp(0.f, yuv[2] + 0.1f * weight, 1.f);
|
||||
const auto &newRgb = filter::yuvToRgb8(yuv.data());
|
||||
memcpy(output.data() + p, newRgb.data(), 3);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace
|
102
plugin/android/src/main/cpp/core/filter/warmth.cpp
Normal file
102
plugin/android/src/main/cpp/core/filter/warmth.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../log.h"
|
||||
#include "curve.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Warmth {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static filter::Curve getRCurve(const float weight);
|
||||
static unique_ptr<filter::Curve> getGCurve(const float weight);
|
||||
static filter::Curve getBCurve(const float weight);
|
||||
|
||||
static constexpr const char *TAG = "Warmth";
|
||||
};
|
||||
|
||||
inline uint8_t weighted(const uint8_t from, const uint8_t to,
|
||||
const float weight) {
|
||||
return (to - from) * weight + from;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
vector<uint8_t> applyWarmth(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
return Warmth().apply(rgba8, width, height, weight);
|
||||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace core
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Warmth::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
const auto rCurve = getRCurve(weight);
|
||||
const auto gCurve = getGCurve(weight);
|
||||
const auto bCurve = getBCurve(weight);
|
||||
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = rCurve.fit(rgba8[p + 0]);
|
||||
output[p + 1] = gCurve ? gCurve->fit(rgba8[p + 1]) : rgba8[p + 1];
|
||||
output[p + 2] = bCurve.fit(rgba8[p + 2]);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
filter::Curve Warmth::getRCurve(const float weight) {
|
||||
if (weight >= 0) {
|
||||
return filter::Curve({0, 78, 195, 255}, {0, weighted(78, 100, weight),
|
||||
weighted(195, 220, weight), 255});
|
||||
} else {
|
||||
return filter::Curve({0, 95, 220, 255},
|
||||
{0, weighted(95, 60, std::abs(weight)),
|
||||
weighted(220, 185, std::abs(weight)), 255});
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<filter::Curve> Warmth::getGCurve(const float weight) {
|
||||
if (weight >= 0) {
|
||||
return make_unique<filter::Curve>(
|
||||
vector<uint8_t>{0, 135, 255},
|
||||
vector<uint8_t>{0, weighted(135, 125, weight), 255});
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
filter::Curve Warmth::getBCurve(const float weight) {
|
||||
if (weight >= 0) {
|
||||
return filter::Curve({0, 95, 220, 255}, {0, weighted(95, 60, weight),
|
||||
weighted(220, 185, weight), 255});
|
||||
} else {
|
||||
return filter::Curve({0, 78, 195, 255},
|
||||
{0, weighted(78, 100, std::abs(weight)),
|
||||
weighted(195, 220, std::abs(weight)), 255});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -2,11 +2,11 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "../math_util.h"
|
||||
#include "./yuv.h"
|
||||
#include "yuv.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace plugin {
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
array<float, 3> rgb8ToYuv(const uint8_t *rgb8) {
|
||||
|
@ -37,4 +37,4 @@ array<uint8_t, 3> yuvToRgb8(const float *yuv) {
|
|||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace plugin
|
||||
} // namespace core
|
|
@ -3,7 +3,7 @@
|
|||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace plugin {
|
||||
namespace core {
|
||||
namespace filter {
|
||||
|
||||
/**
|
||||
|
@ -23,4 +23,4 @@ std::array<float, 3> rgb8ToYuv(const uint8_t *rgb8);
|
|||
std::array<uint8_t, 3> yuvToRgb8(const float *yuv);
|
||||
|
||||
} // namespace filter
|
||||
} // namespace plugin
|
||||
} // namespace core
|
25
plugin/android/src/main/cpp/core/log.h
Normal file
25
plugin/android/src/main/cpp/core/log.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, __VA_ARGS__)
|
||||
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, __VA_ARGS__)
|
||||
#ifdef NDEBUG
|
||||
#define LOGI(...)
|
||||
#define LOGD(...)
|
||||
#define LOGV(...)
|
||||
#else
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, __VA_ARGS__)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, __VA_ARGS__)
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#define LOGE(TAG, MSG, ...) printf("[TAG] MSG", __VA_ARGS__)
|
||||
#define LOGW(TAG, MSG, ...) printf("[TAG] MSG", __VA_ARGS__)
|
||||
#define LOGI(TAG, MSG, ...) printf("[TAG] MSG", __VA_ARGS__)
|
||||
#define LOGD(TAG, MSG, ...) printf("[TAG] MSG", __VA_ARGS__)
|
||||
#define LOGV(TAG, MSG, ...) printf("[TAG] MSG", __VA_ARGS__)
|
||||
|
||||
#endif
|
11
plugin/android/src/main/cpp/core/math_util.h
Normal file
11
plugin/android/src/main/cpp/core/math_util.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace core {
|
||||
|
||||
template <typename T> inline T clamp(const T &min, const T &x, const T &max) {
|
||||
return std::max(min, std::min(x, max));
|
||||
}
|
||||
|
||||
} // namespace core
|
|
@ -1,9 +1,3 @@
|
|||
#include "exception.h"
|
||||
#include "lib/base_resample.h"
|
||||
#include "log.h"
|
||||
#include "stopwatch.h"
|
||||
#include "tflite_wrapper.h"
|
||||
#include "util.h"
|
||||
#include <RenderScriptToolkit.h>
|
||||
#include <algorithm>
|
||||
#include <android/asset_manager.h>
|
||||
|
@ -15,8 +9,15 @@
|
|||
#include <jni.h>
|
||||
#include <tensorflow/lite/c/c_api.h>
|
||||
|
||||
#include "./filter/saturation.h"
|
||||
#include "core/filter/filters.h"
|
||||
#include "core/lib/base_resample.h"
|
||||
#include "exception.h"
|
||||
#include "log.h"
|
||||
#include "stopwatch.h"
|
||||
#include "tflite_wrapper.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace plugin;
|
||||
using namespace renderscript;
|
||||
using namespace std;
|
||||
|
@ -305,8 +306,8 @@ vector<uint8_t> DeepLab3ColorPop::enhance(const uint8_t *image,
|
|||
// desaturate input
|
||||
auto rgba8 = rgb8ToRgba8(image, width, height);
|
||||
vector<uint8_t> desaturate(width * height * 4);
|
||||
plugin::filter::Saturation saturation;
|
||||
desaturate = saturation.apply(rgba8.data(), width, height, -1 * weight);
|
||||
desaturate =
|
||||
filter::applySaturation(rgba8.data(), width, height, -1 * weight);
|
||||
|
||||
// draw input on top of blurred image, with alpha map
|
||||
replaceChannel<4>(rgba8.data(), alphaFiltered.data(), width, height, 3);
|
||||
|
|
|
@ -1,32 +1,15 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <jni.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../core/filter/filters.h"
|
||||
#include "../exception.h"
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "../util.h"
|
||||
#include "./hslhsv.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Brightness {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static constexpr const char *TAG = "Brightness";
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jbyteArray JNICALL
|
||||
Java_com_nkming_nc_1photos_plugin_image_1processor_Brightness_applyNative(
|
||||
JNIEnv *env, jobject *thiz, jbyteArray rgba8, jint width, jint height,
|
||||
|
@ -38,7 +21,7 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Brightness_applyNative(
|
|||
[&](jbyte *obj) {
|
||||
env->ReleaseByteArrayElements(rgba8, obj, JNI_ABORT);
|
||||
});
|
||||
const auto result = Brightness().apply(
|
||||
const auto result = filter::applyBrightness(
|
||||
reinterpret_cast<uint8_t *>(cRgba8.get()), width, height, weight);
|
||||
auto resultAry = env->NewByteArray(result.size());
|
||||
env->SetByteArrayRegion(resultAry, 0, result.size(),
|
||||
|
@ -49,29 +32,3 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Brightness_applyNative(
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Brightness::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const float mul = 1 + weight / 2;
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
auto hsv = filter::rgb8ToHsv(rgba8 + p);
|
||||
hsv[2] = clamp(0.f, hsv[2] * mul, 1.f);
|
||||
const auto &newRgb = filter::hsvToRgb8(hsv.data());
|
||||
memcpy(output.data() + p, newRgb.data(), 3);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1,66 +1,15 @@
|
|||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <jni.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../core/filter/filters.h"
|
||||
#include "../exception.h"
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "../util.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float INPUT_AMPLITUDE = .4f;
|
||||
constexpr uint8_t OUTPUT_AMPLITUDE = 100;
|
||||
|
||||
class WhitePoint {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static uint8_t applyInputLevel(const uint8_t p, const float weight) {
|
||||
const auto pf = p / 255.f;
|
||||
const auto max = 1 - weight * INPUT_AMPLITUDE;
|
||||
return clamp<int>(0, clamp(0.f, pf, max) / max * 255.f, 255);
|
||||
}
|
||||
|
||||
static uint8_t applyOutputLevel(const uint8_t p, const float weight) {
|
||||
return clamp<int>(0, p / 255.f * (255 - weight * OUTPUT_AMPLITUDE), 255);
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> buildLut(const float weight);
|
||||
|
||||
static constexpr const char *TAG = "WhitePoint";
|
||||
};
|
||||
|
||||
class BlackPoint {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static inline uint8_t applyInputLevel(const uint8_t p, const float weight) {
|
||||
const auto pf = p / 255.f;
|
||||
const auto min = weight * INPUT_AMPLITUDE;
|
||||
return clamp<int>(0, (clamp(min, pf, 1.f) - min) / (1 - min) * 255.f, 255);
|
||||
}
|
||||
|
||||
static inline uint8_t applyOutputLevel(const uint8_t p, const float weight) {
|
||||
const auto x = weight * OUTPUT_AMPLITUDE;
|
||||
return clamp<int>(0, p / 255.f * (255 - x) + x, 255);
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> buildLut(const float weight);
|
||||
|
||||
static constexpr const char *TAG = "BlackPoint";
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jbyteArray JNICALL
|
||||
Java_com_nkming_nc_1photos_plugin_image_1processor_WhitePoint_applyNative(
|
||||
JNIEnv *env, jobject *thiz, jbyteArray rgba8, jint width, jint height,
|
||||
|
@ -72,7 +21,7 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_WhitePoint_applyNative(
|
|||
[&](jbyte *obj) {
|
||||
env->ReleaseByteArrayElements(rgba8, obj, JNI_ABORT);
|
||||
});
|
||||
const auto result = WhitePoint().apply(
|
||||
const auto result = filter::applyWhitePoint(
|
||||
reinterpret_cast<uint8_t *>(cRgba8.get()), width, height, weight);
|
||||
auto resultAry = env->NewByteArray(result.size());
|
||||
env->SetByteArrayRegion(resultAry, 0, result.size(),
|
||||
|
@ -95,7 +44,7 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_BlackPoint_applyNative(
|
|||
[&](jbyte *obj) {
|
||||
env->ReleaseByteArrayElements(rgba8, obj, JNI_ABORT);
|
||||
});
|
||||
const auto result = BlackPoint().apply(
|
||||
const auto result = filter::applyBlackPoint(
|
||||
reinterpret_cast<uint8_t *>(cRgba8.get()), width, height, weight);
|
||||
auto resultAry = env->NewByteArray(result.size());
|
||||
env->SetByteArrayRegion(resultAry, 0, result.size(),
|
||||
|
@ -106,73 +55,3 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_BlackPoint_applyNative(
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> WhitePoint::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const auto lut = buildLut(weight);
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = lut[rgba8[p + 0]];
|
||||
output[p + 1] = lut[rgba8[p + 1]];
|
||||
output[p + 2] = lut[rgba8[p + 2]];
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<uint8_t> WhitePoint::buildLut(const float weight) {
|
||||
vector<uint8_t> product(256);
|
||||
const float weightAbs = std::abs(weight);
|
||||
const auto fn =
|
||||
weight > 0 ? &WhitePoint::applyInputLevel : &WhitePoint::applyOutputLevel;
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
product[i] = fn(i, weightAbs);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
vector<uint8_t> BlackPoint::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const auto lut = buildLut(weight);
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = lut[rgba8[p + 0]];
|
||||
output[p + 1] = lut[rgba8[p + 1]];
|
||||
output[p + 2] = lut[rgba8[p + 2]];
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<uint8_t> BlackPoint::buildLut(const float weight) {
|
||||
vector<uint8_t> product(256);
|
||||
const float weightAbs = std::abs(weight);
|
||||
const auto fn =
|
||||
weight > 0 ? &BlackPoint::applyInputLevel : &BlackPoint::applyOutputLevel;
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
product[i] = fn(i, weightAbs);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1,39 +1,15 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <jni.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../core/filter/filters.h"
|
||||
#include "../exception.h"
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "../util.h"
|
||||
#include "./hslhsv.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Contrast {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static constexpr const char *TAG = "Contrast";
|
||||
};
|
||||
|
||||
inline uint8_t applySingle(const uint8_t p, const float mul) {
|
||||
return clamp(0, static_cast<int>((p - 127) * mul + 127), 0xFF);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> buildLut(const float mul);
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jbyteArray JNICALL
|
||||
Java_com_nkming_nc_1photos_plugin_image_1processor_Contrast_applyNative(
|
||||
JNIEnv *env, jobject *thiz, jbyteArray rgba8, jint width, jint height,
|
||||
|
@ -45,7 +21,7 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Contrast_applyNative(
|
|||
[&](jbyte *obj) {
|
||||
env->ReleaseByteArrayElements(rgba8, obj, JNI_ABORT);
|
||||
});
|
||||
const auto result = Contrast().apply(
|
||||
const auto result = filter::applyContrast(
|
||||
reinterpret_cast<uint8_t *>(cRgba8.get()), width, height, weight);
|
||||
auto resultAry = env->NewByteArray(result.size());
|
||||
env->SetByteArrayRegion(resultAry, 0, result.size(),
|
||||
|
@ -56,38 +32,3 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Contrast_applyNative(
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Contrast::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
const float mul = weight >= 0 ? weight + 1 : (weight + 1) * .4f + .6f;
|
||||
const auto lut = buildLut(mul);
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = lut[rgba8[p + 0]];
|
||||
output[p + 1] = lut[rgba8[p + 1]];
|
||||
output[p + 2] = lut[rgba8[p + 2]];
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<uint8_t> buildLut(const float mul) {
|
||||
vector<uint8_t> product(256);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
product[i] = applySingle(i, mul);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <jni.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../core/filter/filters.h"
|
||||
#include "../exception.h"
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "../util.h"
|
||||
#include "./hslhsv.h"
|
||||
#include "./saturation.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
|
||||
|
@ -27,7 +21,7 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Saturation_applyNative(
|
|||
[&](jbyte *obj) {
|
||||
env->ReleaseByteArrayElements(rgba8, obj, JNI_ABORT);
|
||||
});
|
||||
const auto result = filter::Saturation().apply(
|
||||
const auto result = filter::applySaturation(
|
||||
reinterpret_cast<uint8_t *>(cRgba8.get()), width, height, value);
|
||||
auto resultAry = env->NewByteArray(result.size());
|
||||
env->SetByteArrayRegion(resultAry, 0, result.size(),
|
||||
|
@ -38,30 +32,3 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Saturation_applyNative(
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace plugin {
|
||||
namespace filter {
|
||||
|
||||
vector<uint8_t> Saturation::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
auto hsl = filter::rgb8ToHsl(rgba8 + p);
|
||||
hsl[1] = clamp(0.f, hsl[1] * (1 + weight), 1.f);
|
||||
const auto &newRgb = filter::hslToRgb8(hsl.data());
|
||||
memcpy(output.data() + p, newRgb.data(), 3);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
}
|
||||
|
|
|
@ -1,31 +1,15 @@
|
|||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <jni.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../core/filter/filters.h"
|
||||
#include "../exception.h"
|
||||
#include "../log.h"
|
||||
#include "../math_util.h"
|
||||
#include "../util.h"
|
||||
#include "./yuv.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Tint {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static constexpr const char *TAG = "Tint";
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jbyteArray JNICALL
|
||||
Java_com_nkming_nc_1photos_plugin_image_1processor_Tint_applyNative(
|
||||
JNIEnv *env, jobject *thiz, jbyteArray rgba8, jint width, jint height,
|
||||
|
@ -37,8 +21,8 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Tint_applyNative(
|
|||
[&](jbyte *obj) {
|
||||
env->ReleaseByteArrayElements(rgba8, obj, JNI_ABORT);
|
||||
});
|
||||
const auto result = Tint().apply(reinterpret_cast<uint8_t *>(cRgba8.get()),
|
||||
width, height, weight);
|
||||
const auto result = filter::applyTint(
|
||||
reinterpret_cast<uint8_t *>(cRgba8.get()), width, height, weight);
|
||||
auto resultAry = env->NewByteArray(result.size());
|
||||
env->SetByteArrayRegion(resultAry, 0, result.size(),
|
||||
reinterpret_cast<const int8_t *>(result.data()));
|
||||
|
@ -48,30 +32,3 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Tint_applyNative(
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Tint::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
auto yuv = filter::rgb8ToYuv(rgba8 + p);
|
||||
// +-0.1
|
||||
yuv[1] = clamp(0.f, yuv[1] + 0.1f * weight, 1.f);
|
||||
yuv[2] = clamp(0.f, yuv[2] + 0.1f * weight, 1.f);
|
||||
const auto &newRgb = filter::yuvToRgb8(yuv.data());
|
||||
memcpy(output.data() + p, newRgb.data(), 3);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1,40 +1,15 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <jni.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../core/filter/filters.h"
|
||||
#include "../exception.h"
|
||||
#include "../log.h"
|
||||
#include "../util.h"
|
||||
#include "./curve.h"
|
||||
|
||||
using namespace core;
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
class Warmth {
|
||||
public:
|
||||
std::vector<uint8_t> apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight);
|
||||
|
||||
private:
|
||||
static filter::Curve getRCurve(const float weight);
|
||||
static unique_ptr<filter::Curve> getGCurve(const float weight);
|
||||
static filter::Curve getBCurve(const float weight);
|
||||
|
||||
static constexpr const char *TAG = "Warmth";
|
||||
};
|
||||
|
||||
inline uint8_t weighted(const uint8_t from, const uint8_t to,
|
||||
const float weight) {
|
||||
return (to - from) * weight + from;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jbyteArray JNICALL
|
||||
Java_com_nkming_nc_1photos_plugin_image_1processor_Warmth_applyNative(
|
||||
JNIEnv *env, jobject *thiz, jbyteArray rgba8, jint width, jint height,
|
||||
|
@ -46,7 +21,7 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Warmth_applyNative(
|
|||
[&](jbyte *obj) {
|
||||
env->ReleaseByteArrayElements(rgba8, obj, JNI_ABORT);
|
||||
});
|
||||
const auto result = Warmth().apply(
|
||||
const auto result = filter::applyWarmth(
|
||||
reinterpret_cast<uint8_t *>(cRgba8.get()), width, height, weight);
|
||||
auto resultAry = env->NewByteArray(result.size());
|
||||
env->SetByteArrayRegion(resultAry, 0, result.size(),
|
||||
|
@ -57,62 +32,3 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Warmth_applyNative(
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
vector<uint8_t> Warmth::apply(const uint8_t *rgba8, const size_t width,
|
||||
const size_t height, const float weight) {
|
||||
LOGI(TAG, "[apply] weight: %.2f", weight);
|
||||
if (weight == 0) {
|
||||
// shortcut
|
||||
return vector<uint8_t>(rgba8, rgba8 + width * height * 4);
|
||||
}
|
||||
const auto rCurve = getRCurve(weight);
|
||||
const auto gCurve = getGCurve(weight);
|
||||
const auto bCurve = getBCurve(weight);
|
||||
|
||||
vector<uint8_t> output(width * height * 4);
|
||||
#pragma omp parallel for
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
const auto p = i * 4;
|
||||
output[p + 0] = rCurve.fit(rgba8[p + 0]);
|
||||
output[p + 1] = gCurve ? gCurve->fit(rgba8[p + 1]) : rgba8[p + 1];
|
||||
output[p + 2] = bCurve.fit(rgba8[p + 2]);
|
||||
output[p + 3] = rgba8[p + 3];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
filter::Curve Warmth::getRCurve(const float weight) {
|
||||
if (weight >= 0) {
|
||||
return filter::Curve({0, 78, 195, 255}, {0, weighted(78, 100, weight),
|
||||
weighted(195, 220, weight), 255});
|
||||
} else {
|
||||
return filter::Curve({0, 95, 220, 255},
|
||||
{0, weighted(95, 60, std::abs(weight)),
|
||||
weighted(220, 185, std::abs(weight)), 255});
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<filter::Curve> Warmth::getGCurve(const float weight) {
|
||||
if (weight >= 0) {
|
||||
return make_unique<filter::Curve>(
|
||||
vector<uint8_t>{0, 135, 255},
|
||||
vector<uint8_t>{0, weighted(135, 125, weight), 255});
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
filter::Curve Warmth::getBCurve(const float weight) {
|
||||
if (weight >= 0) {
|
||||
return filter::Curve({0, 95, 220, 255}, {0, weighted(95, 60, weight),
|
||||
weighted(220, 185, weight), 255});
|
||||
} else {
|
||||
return filter::Curve({0, 78, 195, 255},
|
||||
{0, weighted(78, 100, std::abs(weight)),
|
||||
weighted(195, 220, std::abs(weight)), 255});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
#include "exception.h"
|
||||
#include "lib/base_resample.h"
|
||||
#include "log.h"
|
||||
#include "stopwatch.h"
|
||||
#include "tflite_wrapper.h"
|
||||
#include "util.h"
|
||||
#include <algorithm>
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
|
@ -12,6 +6,13 @@
|
|||
#include <jni.h>
|
||||
#include <tensorflow/lite/c/c_api.h>
|
||||
|
||||
#include "core/lib/base_resample.h"
|
||||
#include "exception.h"
|
||||
#include "log.h"
|
||||
#include "stopwatch.h"
|
||||
#include "tflite_wrapper.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace plugin;
|
||||
using namespace std;
|
||||
using namespace tflite;
|
||||
|
|
Loading…
Reference in a new issue