From bca748ded3bfd87f42df4a9bf6b1cee4000f5562 Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Tue, 29 Aug 2023 23:50:57 +0800 Subject: [PATCH] Group platform independent c++ code --- plugin/android/src/main/cpp/CMakeLists.txt | 14 +- .../src/main/cpp/arbitrary_style_transfer.cpp | 13 +- .../src/main/cpp/core/filter/brightness.cpp | 61 ++++++++ .../src/main/cpp/core/filter/color_levels.cpp | 144 ++++++++++++++++++ .../src/main/cpp/core/filter/contrast.cpp | 77 ++++++++++ .../src/main/cpp/{ => core}/filter/curve.cpp | 14 +- .../src/main/cpp/{ => core}/filter/curve.h | 4 +- .../src/main/cpp/core/filter/filters.h | 30 ++++ .../src/main/cpp/{ => core}/filter/hslhsv.cpp | 6 +- .../src/main/cpp/{ => core}/filter/hslhsv.h | 4 +- .../src/main/cpp/core/filter/saturation.cpp | 44 ++++++ .../main/cpp/{ => core}/filter/saturation.h | 4 +- .../android/src/main/cpp/core/filter/tint.cpp | 62 ++++++++ .../src/main/cpp/core/filter/warmth.cpp | 102 +++++++++++++ .../src/main/cpp/{ => core}/filter/yuv.cpp | 6 +- .../src/main/cpp/{ => core}/filter/yuv.h | 4 +- .../main/cpp/{ => core}/lib/base_resample.h | 0 .../main/cpp/{ => core}/lib/spline/LICENSE | 0 .../main/cpp/{ => core}/lib/spline/spline.cpp | 0 .../main/cpp/{ => core}/lib/spline/spline.h | 0 plugin/android/src/main/cpp/core/log.h | 25 +++ plugin/android/src/main/cpp/core/math_util.h | 11 ++ plugin/android/src/main/cpp/deep_lap_3.cpp | 19 +-- .../src/main/cpp/filter/brightness.cpp | 49 +----- .../src/main/cpp/filter/color_levels.cpp | 129 +--------------- .../android/src/main/cpp/filter/contrast.cpp | 65 +------- .../src/main/cpp/filter/saturation.cpp | 39 +---- plugin/android/src/main/cpp/filter/tint.cpp | 51 +------ plugin/android/src/main/cpp/filter/warmth.cpp | 90 +---------- plugin/android/src/main/cpp/zero_dce.cpp | 13 +- 30 files changed, 631 insertions(+), 449 deletions(-) create mode 100644 plugin/android/src/main/cpp/core/filter/brightness.cpp create mode 100644 plugin/android/src/main/cpp/core/filter/color_levels.cpp create mode 100644 plugin/android/src/main/cpp/core/filter/contrast.cpp rename plugin/android/src/main/cpp/{ => core}/filter/curve.cpp (80%) rename plugin/android/src/main/cpp/{ => core}/filter/curve.h (92%) create mode 100644 plugin/android/src/main/cpp/core/filter/filters.h rename plugin/android/src/main/cpp/{ => core}/filter/hslhsv.cpp (98%) rename plugin/android/src/main/cpp/{ => core}/filter/hslhsv.h (90%) create mode 100644 plugin/android/src/main/cpp/core/filter/saturation.cpp rename plugin/android/src/main/cpp/{ => core}/filter/saturation.h (88%) create mode 100644 plugin/android/src/main/cpp/core/filter/tint.cpp create mode 100644 plugin/android/src/main/cpp/core/filter/warmth.cpp rename plugin/android/src/main/cpp/{ => core}/filter/yuv.cpp (94%) rename plugin/android/src/main/cpp/{ => core}/filter/yuv.h (90%) rename plugin/android/src/main/cpp/{ => core}/lib/base_resample.h (100%) rename plugin/android/src/main/cpp/{ => core}/lib/spline/LICENSE (100%) rename plugin/android/src/main/cpp/{ => core}/lib/spline/spline.cpp (100%) rename plugin/android/src/main/cpp/{ => core}/lib/spline/spline.h (100%) create mode 100644 plugin/android/src/main/cpp/core/log.h create mode 100644 plugin/android/src/main/cpp/core/math_util.h diff --git a/plugin/android/src/main/cpp/CMakeLists.txt b/plugin/android/src/main/cpp/CMakeLists.txt index 834e8ded..76764557 100644 --- a/plugin/android/src/main/cpp/CMakeLists.txt +++ b/plugin/android/src/main/cpp/CMakeLists.txt @@ -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 diff --git a/plugin/android/src/main/cpp/arbitrary_style_transfer.cpp b/plugin/android/src/main/cpp/arbitrary_style_transfer.cpp index d34d9a53..bc5ad5d7 100644 --- a/plugin/android/src/main/cpp/arbitrary_style_transfer.cpp +++ b/plugin/android/src/main/cpp/arbitrary_style_transfer.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 #include #include @@ -14,6 +8,13 @@ #include #include +#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; diff --git a/plugin/android/src/main/cpp/core/filter/brightness.cpp b/plugin/android/src/main/cpp/core/filter/brightness.cpp new file mode 100644 index 00000000..2cb987cb --- /dev/null +++ b/plugin/android/src/main/cpp/core/filter/brightness.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +#include "../log.h" +#include "../math_util.h" +#include "hslhsv.h" + +using namespace core; +using namespace std; + +namespace { + +class Brightness { +public: + std::vector 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 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 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(rgba8, rgba8 + width * height * 4); + } + + const float mul = 1 + weight / 2; + vector 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 diff --git a/plugin/android/src/main/cpp/core/filter/color_levels.cpp b/plugin/android/src/main/cpp/core/filter/color_levels.cpp new file mode 100644 index 00000000..02b0bbea --- /dev/null +++ b/plugin/android/src/main/cpp/core/filter/color_levels.cpp @@ -0,0 +1,144 @@ +#include +#include + +#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 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(0, clamp(0.f, pf, max) / max * 255.f, 255); + } + + static uint8_t applyOutputLevel(const uint8_t p, const float weight) { + return clamp(0, p / 255.f * (255 - weight * OUTPUT_AMPLITUDE), 255); + } + + static std::vector buildLut(const float weight); + + static constexpr const char *TAG = "WhitePoint"; +}; + +class BlackPoint { +public: + std::vector 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(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(0, p / 255.f * (255 - x) + x, 255); + } + + static std::vector buildLut(const float weight); + + static constexpr const char *TAG = "BlackPoint"; +}; + +} // namespace + +namespace core { +namespace filter { + +vector applyWhitePoint(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight) { + return WhitePoint().apply(rgba8, width, height, weight); +} + +vector 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 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(rgba8, rgba8 + width * height * 4); + } + + const auto lut = buildLut(weight); + vector 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 WhitePoint::buildLut(const float weight) { + vector 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 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(rgba8, rgba8 + width * height * 4); + } + + const auto lut = buildLut(weight); + vector 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 BlackPoint::buildLut(const float weight) { + vector 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 diff --git a/plugin/android/src/main/cpp/core/filter/contrast.cpp b/plugin/android/src/main/cpp/core/filter/contrast.cpp new file mode 100644 index 00000000..fc4788bd --- /dev/null +++ b/plugin/android/src/main/cpp/core/filter/contrast.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +#include "../log.h" +#include "../math_util.h" +#include "hslhsv.h" + +using namespace core; +using namespace std; + +namespace { + +class Contrast { +public: + std::vector 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((p - 127) * mul + 127), 0xFF); +} + +std::vector buildLut(const float mul); + +} // namespace + +namespace core { +namespace filter { + +vector 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 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(rgba8, rgba8 + width * height * 4); + } + + const float mul = weight >= 0 ? weight + 1 : (weight + 1) * .4f + .6f; + const auto lut = buildLut(mul); + vector 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 buildLut(const float mul) { + vector product(256); +#pragma omp parallel for + for (size_t i = 0; i < 256; ++i) { + product[i] = applySingle(i, mul); + } + return product; +} + +} // namespace diff --git a/plugin/android/src/main/cpp/filter/curve.cpp b/plugin/android/src/main/cpp/core/filter/curve.cpp similarity index 80% rename from plugin/android/src/main/cpp/filter/curve.cpp rename to plugin/android/src/main/cpp/core/filter/curve.cpp index 3fae3dbb..7f95805f 100644 --- a/plugin/android/src/main/cpp/filter/curve.cpp +++ b/plugin/android/src/main/cpp/core/filter/curve.cpp @@ -3,7 +3,7 @@ #include #include "../lib/spline/spline.h" -#include "./curve.h" +#include "curve.h" using namespace std; @@ -11,23 +11,23 @@ namespace { std::vector buildLut(const vector &from, const vector &to); -vector transformPoints(const vector &pts); +std::vector transformPoints(const vector &pts); } // namespace -namespace plugin { +namespace core { namespace filter { Curve::Curve(const vector &from, const vector &to) : lut(buildLut(from, to)) {} } // namespace filter -} // namespace plugin +} // namespace core namespace { -std::vector buildLut(const vector &from, - const vector &to) { +vector buildLut(const vector &from, + const vector &to) { assert(from.size() >= 2); assert(from[0] == 0); assert(from[from.size() - 1] == 255); @@ -36,7 +36,7 @@ std::vector buildLut(const vector &from, assert(to[to.size() - 1] == 255); tk::spline spline(transformPoints(from), transformPoints(to), tk::spline::cspline_hermite); - std::vector lut; + vector lut; lut.reserve(256); for (int i = 0; i <= 0xFF; ++i) { lut.push_back(std::min(std::max(0, static_cast(spline(i))), 0xFF)); diff --git a/plugin/android/src/main/cpp/filter/curve.h b/plugin/android/src/main/cpp/core/filter/curve.h similarity index 92% rename from plugin/android/src/main/cpp/filter/curve.h rename to plugin/android/src/main/cpp/core/filter/curve.h index a9e6a59d..f7da8a81 100644 --- a/plugin/android/src/main/cpp/filter/curve.h +++ b/plugin/android/src/main/cpp/core/filter/curve.h @@ -1,7 +1,7 @@ #include #include -namespace plugin { +namespace core { namespace filter { class Curve { @@ -23,4 +23,4 @@ private: }; } // namespace filter -} // namespace plugin +} // namespace core diff --git a/plugin/android/src/main/cpp/core/filter/filters.h b/plugin/android/src/main/cpp/core/filter/filters.h new file mode 100644 index 00000000..145f7741 --- /dev/null +++ b/plugin/android/src/main/cpp/core/filter/filters.h @@ -0,0 +1,30 @@ +#include +#include +#include + +namespace core { +namespace filter { + +std::vector applyBrightness(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight); + +std::vector applyWhitePoint(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight); + +std::vector applyBlackPoint(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight); + +std::vector applyContrast(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight); + +std::vector applySaturation(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight); + +std::vector applyTint(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight); + +std::vector applyWarmth(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight); + +} // namespace filter +} // namespace core diff --git a/plugin/android/src/main/cpp/filter/hslhsv.cpp b/plugin/android/src/main/cpp/core/filter/hslhsv.cpp similarity index 98% rename from plugin/android/src/main/cpp/filter/hslhsv.cpp rename to plugin/android/src/main/cpp/core/filter/hslhsv.cpp index cda03bd8..25b7d556 100644 --- a/plugin/android/src/main/cpp/filter/hslhsv.cpp +++ b/plugin/android/src/main/cpp/core/filter/hslhsv.cpp @@ -4,11 +4,11 @@ #include #include "../math_util.h" -#include "./hslhsv.h" +#include "hslhsv.h" using namespace std; -namespace plugin { +namespace core { namespace filter { array rgb8ToHsl(const uint8_t *rgb8) { @@ -167,4 +167,4 @@ std::array hsvToHsl(const float *hsv) { } } // namespace filter -} // namespace plugin +} // namespace core diff --git a/plugin/android/src/main/cpp/filter/hslhsv.h b/plugin/android/src/main/cpp/core/filter/hslhsv.h similarity index 90% rename from plugin/android/src/main/cpp/filter/hslhsv.h rename to plugin/android/src/main/cpp/core/filter/hslhsv.h index 07d71cdf..6cc958b5 100644 --- a/plugin/android/src/main/cpp/filter/hslhsv.h +++ b/plugin/android/src/main/cpp/core/filter/hslhsv.h @@ -3,7 +3,7 @@ #include #include -namespace plugin { +namespace core { namespace filter { std::array rgb8ToHsl(const uint8_t *rgb8); @@ -16,4 +16,4 @@ std::array hslToHsv(const float *hsl); std::array hsvToHsl(const float *hsv); } // namespace filter -} // namespace plugin +} // namespace core diff --git a/plugin/android/src/main/cpp/core/filter/saturation.cpp b/plugin/android/src/main/cpp/core/filter/saturation.cpp new file mode 100644 index 00000000..81726074 --- /dev/null +++ b/plugin/android/src/main/cpp/core/filter/saturation.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +#include "../log.h" +#include "../math_util.h" +#include "hslhsv.h" +#include "saturation.h" + +using namespace std; + +namespace core { +namespace filter { + +vector applySaturation(const uint8_t *rgba8, const size_t width, + const size_t height, const float weight) { + return Saturation().apply(rgba8, width, height, weight); +} + +vector 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(rgba8, rgba8 + width * height * 4); + } + + vector 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 diff --git a/plugin/android/src/main/cpp/filter/saturation.h b/plugin/android/src/main/cpp/core/filter/saturation.h similarity index 88% rename from plugin/android/src/main/cpp/filter/saturation.h rename to plugin/android/src/main/cpp/core/filter/saturation.h index 3530a09b..e6d62a7b 100644 --- a/plugin/android/src/main/cpp/filter/saturation.h +++ b/plugin/android/src/main/cpp/core/filter/saturation.h @@ -1,7 +1,7 @@ #include #include -namespace plugin { +namespace core { namespace filter { class Saturation { @@ -14,4 +14,4 @@ private: }; } // namespace filter -} // namespace plugin +} // namespace core diff --git a/plugin/android/src/main/cpp/core/filter/tint.cpp b/plugin/android/src/main/cpp/core/filter/tint.cpp new file mode 100644 index 00000000..e71ee8a0 --- /dev/null +++ b/plugin/android/src/main/cpp/core/filter/tint.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "../log.h" +#include "../math_util.h" +#include "yuv.h" + +using namespace core; +using namespace std; + +namespace { + +class Tint { +public: + std::vector 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 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 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(rgba8, rgba8 + width * height * 4); + } + + vector 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 diff --git a/plugin/android/src/main/cpp/core/filter/warmth.cpp b/plugin/android/src/main/cpp/core/filter/warmth.cpp new file mode 100644 index 00000000..acd35b8f --- /dev/null +++ b/plugin/android/src/main/cpp/core/filter/warmth.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +#include "../log.h" +#include "curve.h" + +using namespace core; +using namespace std; + +namespace { + +class Warmth { +public: + std::vector 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 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 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 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(rgba8, rgba8 + width * height * 4); + } + const auto rCurve = getRCurve(weight); + const auto gCurve = getGCurve(weight); + const auto bCurve = getBCurve(weight); + + vector 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 Warmth::getGCurve(const float weight) { + if (weight >= 0) { + return make_unique( + vector{0, 135, 255}, + vector{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 diff --git a/plugin/android/src/main/cpp/filter/yuv.cpp b/plugin/android/src/main/cpp/core/filter/yuv.cpp similarity index 94% rename from plugin/android/src/main/cpp/filter/yuv.cpp rename to plugin/android/src/main/cpp/core/filter/yuv.cpp index aec8047a..c09852c7 100644 --- a/plugin/android/src/main/cpp/filter/yuv.cpp +++ b/plugin/android/src/main/cpp/core/filter/yuv.cpp @@ -2,11 +2,11 @@ #include #include "../math_util.h" -#include "./yuv.h" +#include "yuv.h" using namespace std; -namespace plugin { +namespace core { namespace filter { array rgb8ToYuv(const uint8_t *rgb8) { @@ -37,4 +37,4 @@ array yuvToRgb8(const float *yuv) { } } // namespace filter -} // namespace plugin +} // namespace core diff --git a/plugin/android/src/main/cpp/filter/yuv.h b/plugin/android/src/main/cpp/core/filter/yuv.h similarity index 90% rename from plugin/android/src/main/cpp/filter/yuv.h rename to plugin/android/src/main/cpp/core/filter/yuv.h index 0cd99946..48e779e1 100644 --- a/plugin/android/src/main/cpp/filter/yuv.h +++ b/plugin/android/src/main/cpp/core/filter/yuv.h @@ -3,7 +3,7 @@ #include #include -namespace plugin { +namespace core { namespace filter { /** @@ -23,4 +23,4 @@ std::array rgb8ToYuv(const uint8_t *rgb8); std::array yuvToRgb8(const float *yuv); } // namespace filter -} // namespace plugin +} // namespace core diff --git a/plugin/android/src/main/cpp/lib/base_resample.h b/plugin/android/src/main/cpp/core/lib/base_resample.h similarity index 100% rename from plugin/android/src/main/cpp/lib/base_resample.h rename to plugin/android/src/main/cpp/core/lib/base_resample.h diff --git a/plugin/android/src/main/cpp/lib/spline/LICENSE b/plugin/android/src/main/cpp/core/lib/spline/LICENSE similarity index 100% rename from plugin/android/src/main/cpp/lib/spline/LICENSE rename to plugin/android/src/main/cpp/core/lib/spline/LICENSE diff --git a/plugin/android/src/main/cpp/lib/spline/spline.cpp b/plugin/android/src/main/cpp/core/lib/spline/spline.cpp similarity index 100% rename from plugin/android/src/main/cpp/lib/spline/spline.cpp rename to plugin/android/src/main/cpp/core/lib/spline/spline.cpp diff --git a/plugin/android/src/main/cpp/lib/spline/spline.h b/plugin/android/src/main/cpp/core/lib/spline/spline.h similarity index 100% rename from plugin/android/src/main/cpp/lib/spline/spline.h rename to plugin/android/src/main/cpp/core/lib/spline/spline.h diff --git a/plugin/android/src/main/cpp/core/log.h b/plugin/android/src/main/cpp/core/log.h new file mode 100644 index 00000000..cbb45293 --- /dev/null +++ b/plugin/android/src/main/cpp/core/log.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef __ANDROID__ +#include + +#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 diff --git a/plugin/android/src/main/cpp/core/math_util.h b/plugin/android/src/main/cpp/core/math_util.h new file mode 100644 index 00000000..d7d1fea7 --- /dev/null +++ b/plugin/android/src/main/cpp/core/math_util.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace core { + +template inline T clamp(const T &min, const T &x, const T &max) { + return std::max(min, std::min(x, max)); +} + +} // namespace core diff --git a/plugin/android/src/main/cpp/deep_lap_3.cpp b/plugin/android/src/main/cpp/deep_lap_3.cpp index dc4fe944..b62d47dc 100644 --- a/plugin/android/src/main/cpp/deep_lap_3.cpp +++ b/plugin/android/src/main/cpp/deep_lap_3.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 #include #include @@ -15,8 +9,15 @@ #include #include -#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 DeepLab3ColorPop::enhance(const uint8_t *image, // desaturate input auto rgba8 = rgb8ToRgba8(image, width, height); vector 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); diff --git a/plugin/android/src/main/cpp/filter/brightness.cpp b/plugin/android/src/main/cpp/filter/brightness.cpp index e515c78e..cc99355d 100644 --- a/plugin/android/src/main/cpp/filter/brightness.cpp +++ b/plugin/android/src/main/cpp/filter/brightness.cpp @@ -1,32 +1,15 @@ -#include #include -#include #include #include -#include +#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 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(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 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(rgba8, rgba8 + width * height * 4); - } - - const float mul = 1 + weight / 2; - vector 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 diff --git a/plugin/android/src/main/cpp/filter/color_levels.cpp b/plugin/android/src/main/cpp/filter/color_levels.cpp index da3873c4..66826a6c 100644 --- a/plugin/android/src/main/cpp/filter/color_levels.cpp +++ b/plugin/android/src/main/cpp/filter/color_levels.cpp @@ -1,66 +1,15 @@ #include #include #include -#include +#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 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(0, clamp(0.f, pf, max) / max * 255.f, 255); - } - - static uint8_t applyOutputLevel(const uint8_t p, const float weight) { - return clamp(0, p / 255.f * (255 - weight * OUTPUT_AMPLITUDE), 255); - } - - static std::vector buildLut(const float weight); - - static constexpr const char *TAG = "WhitePoint"; -}; - -class BlackPoint { -public: - std::vector 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(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(0, p / 255.f * (255 - x) + x, 255); - } - - static std::vector 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(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(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 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(rgba8, rgba8 + width * height * 4); - } - - const auto lut = buildLut(weight); - vector 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 WhitePoint::buildLut(const float weight) { - vector 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 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(rgba8, rgba8 + width * height * 4); - } - - const auto lut = buildLut(weight); - vector 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 BlackPoint::buildLut(const float weight) { - vector 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 diff --git a/plugin/android/src/main/cpp/filter/contrast.cpp b/plugin/android/src/main/cpp/filter/contrast.cpp index 3eb820de..c005f6bd 100644 --- a/plugin/android/src/main/cpp/filter/contrast.cpp +++ b/plugin/android/src/main/cpp/filter/contrast.cpp @@ -1,39 +1,15 @@ -#include #include -#include #include #include -#include -#include +#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 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((p - 127) * mul + 127), 0xFF); -} - -std::vector 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(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 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(rgba8, rgba8 + width * height * 4); - } - - const float mul = weight >= 0 ? weight + 1 : (weight + 1) * .4f + .6f; - const auto lut = buildLut(mul); - vector 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 buildLut(const float mul) { - vector product(256); -#pragma omp parallel for - for (size_t i = 0; i < 256; ++i) { - product[i] = applySingle(i, mul); - } - return product; -} - -} // namespace diff --git a/plugin/android/src/main/cpp/filter/saturation.cpp b/plugin/android/src/main/cpp/filter/saturation.cpp index fb60a253..1abfbe66 100644 --- a/plugin/android/src/main/cpp/filter/saturation.cpp +++ b/plugin/android/src/main/cpp/filter/saturation.cpp @@ -1,18 +1,12 @@ -#include #include -#include #include #include -#include -#include +#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(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 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(rgba8, rgba8 + width * height * 4); - } - - vector 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 -} diff --git a/plugin/android/src/main/cpp/filter/tint.cpp b/plugin/android/src/main/cpp/filter/tint.cpp index 447fca2b..2669f4b2 100644 --- a/plugin/android/src/main/cpp/filter/tint.cpp +++ b/plugin/android/src/main/cpp/filter/tint.cpp @@ -1,31 +1,15 @@ #include -#include #include #include -#include +#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 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(cRgba8.get()), - width, height, weight); + const auto result = filter::applyTint( + reinterpret_cast(cRgba8.get()), width, height, weight); auto resultAry = env->NewByteArray(result.size()); env->SetByteArrayRegion(resultAry, 0, result.size(), reinterpret_cast(result.data())); @@ -48,30 +32,3 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_Tint_applyNative( return nullptr; } } - -namespace { - -vector 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(rgba8, rgba8 + width * height * 4); - } - - vector 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 diff --git a/plugin/android/src/main/cpp/filter/warmth.cpp b/plugin/android/src/main/cpp/filter/warmth.cpp index a3ae7af2..e0793420 100644 --- a/plugin/android/src/main/cpp/filter/warmth.cpp +++ b/plugin/android/src/main/cpp/filter/warmth.cpp @@ -1,40 +1,15 @@ -#include #include #include #include -#include -#include +#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 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 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(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 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(rgba8, rgba8 + width * height * 4); - } - const auto rCurve = getRCurve(weight); - const auto gCurve = getGCurve(weight); - const auto bCurve = getBCurve(weight); - - vector 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 Warmth::getGCurve(const float weight) { - if (weight >= 0) { - return make_unique( - vector{0, 135, 255}, - vector{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 diff --git a/plugin/android/src/main/cpp/zero_dce.cpp b/plugin/android/src/main/cpp/zero_dce.cpp index 55e9763c..528a7349 100644 --- a/plugin/android/src/main/cpp/zero_dce.cpp +++ b/plugin/android/src/main/cpp/zero_dce.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 #include #include @@ -12,6 +6,13 @@ #include #include +#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;