diff --git a/libs/image/src/ImageOps.cpp b/libs/image/src/ImageOps.cpp index 7edb16ff59..36da604961 100644 --- a/libs/image/src/ImageOps.cpp +++ b/libs/image/src/ImageOps.cpp @@ -17,10 +17,12 @@ #include #include +#include #include #include #include +#include using namespace math; @@ -117,28 +119,38 @@ LinearImage verticalFlip(const LinearImage& image) { return result; } -LinearImage vectorsToColors(const LinearImage& image) { - ASSERT_PRECONDITION(image.getChannels() == 3, "Must be a 3-channel image."); +template , + class Offset = std::ratio<1, 1>> +LinearImage applyScaleOffset(const LinearImage& image) { const uint32_t width = image.getWidth(), height = image.getHeight(); - LinearImage result(width, height, 3); - auto src = (float3 const*) image.getPixelRef(); - auto dst = (float3*) result.getPixelRef(); + LinearImage result(width, height, image.getChannels()); + auto src = (VecT const*) image.getPixelRef(); + auto dst = (VecT*) result.getPixelRef(); + constexpr float scale_f = + static_cast(Scale::num) / static_cast(Scale::den); + constexpr float offset_f = + static_cast(Offset::num) / static_cast(Offset::den); for (uint32_t n = 0, end = width * height; n < end; ++n) { - dst[n] = 0.5f * (src[n] + float3(1)); + dst[n] = scale_f * src[n] + VecT(offset_f); } return result; } +LinearImage vectorsToColors(const LinearImage& image) { + ASSERT_PRECONDITION(image.getChannels() == 3 || image.getChannels() == 4, + "Must be a 3 or 4 channel image"); + return image.getChannels() == 3 + ? applyScaleOffset, std::ratio<1, 2>>(image) + : applyScaleOffset, std::ratio<1, 2>>(image); +} + LinearImage colorsToVectors(const LinearImage& image) { - ASSERT_PRECONDITION(image.getChannels() == 3, "Must be a 3-channel image."); - const uint32_t width = image.getWidth(), height = image.getHeight(); - LinearImage result(width, height, 3); - auto src = (float3 const*) image.getPixelRef(); - auto dst = (float3*) result.getPixelRef(); - for (uint32_t n = 0, end = width * height; n < end; ++n) { - dst[n] = 2.0f * src[n] - float3(1); - } - return result; + ASSERT_PRECONDITION(image.getChannels() == 3 || image.getChannels() == 4, + "Must be a 3 or 4 channel image"); + return image.getChannels() == 3 + ? applyScaleOffset, std::ratio<-1, 1>>(image) + : applyScaleOffset, std::ratio<-1, 1>>(image); } LinearImage extractChannel(const LinearImage& source, uint32_t channel) { diff --git a/libs/image/src/ImageSampler.cpp b/libs/image/src/ImageSampler.cpp index db6f0d1f63..aabd3bfcb1 100644 --- a/libs/image/src/ImageSampler.cpp +++ b/libs/image/src/ImageSampler.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -204,15 +205,25 @@ FilterFunction createFilterFunction(Filter ftype) { return fn; } -void normalize(LinearImage& image) { - ASSERT_PRECONDITION(image.getChannels() == 3, "Must be a 3-channel image."); +template +void normalizeImpl(LinearImage& image) { const uint32_t width = image.getWidth(), height = image.getHeight(); - auto vecs = (math::float3*) image.getPixelRef(); + auto vecs = (VecT*) image.getPixelRef(); for (uint32_t n = 0; n < width * height; ++n) { vecs[n] = normalize(vecs[n]); } } +void normalize(LinearImage& image) { + ASSERT_PRECONDITION(image.getChannels() == 3 || image.getChannels() == 4, + "Must be a 3 or 4 channel image"); + if (image.getChannels() == 3) { + normalizeImpl(image); + } else { + normalizeImpl(image); + } +} + LinearImage resampleImage1D(const LinearImage& source, MadProgram* program, uint32_t twidth, Filter filter, float left, float right, float filterRadiusMultiplier) { const uint32_t swidth = source.getWidth();