Skip to content

Commit

Permalink
Added ProcessTexels to easily (albeit inefficiently) run a custom pro…
Browse files Browse the repository at this point in the history
…cess on an image
  • Loading branch information
vk2gpu committed Jan 15, 2018
1 parent 682a301 commit 622f691
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 54 deletions.
8 changes: 4 additions & 4 deletions src/image/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Image

public:
HSVColor();
HSVColor(f32* val);
HSVColor(const f32* val);
HSVColor(f32 h, f32 s, f32 v);
};

Expand All @@ -28,7 +28,7 @@ namespace Image

public:
YCoCgColor();
YCoCgColor(f32* val);
YCoCgColor(const f32* val);
YCoCgColor(f32 y, f32 co, f32 cg);
};

Expand All @@ -42,7 +42,7 @@ namespace Image

public:
SRGBAColor();
SRGBAColor(u8* val);
SRGBAColor(const u8* val);
SRGBAColor(u8 r, u8 g, u8 b, u8 a);

operator u32() const { return (a << 24) | (b << 16) | (g << 8) | r; }
Expand All @@ -59,7 +59,7 @@ namespace Image

public:
RGBAColor();
RGBAColor(f32* val);
RGBAColor(const f32* val);
RGBAColor(f32 r, f32 g, f32 b, f32 a);

RGBAColor operator+(const RGBAColor& Rhs) const
Expand Down
44 changes: 22 additions & 22 deletions src/image/ispc/image_processing.ispc
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,36 @@ export struct Color_R8G8B8A8
u8 r, g, b, a;
};

static inline float SingleToSRGB(float linearCol)
{
const float sRGBLo = linearCol * 12.92f;
const float sRGBHi = (pow(abs(linearCol), 1.0f / 2.4f) * 1.055f) - 0.055f;
const float sRGB = (linearCol <= 0.0031308f) ? sRGBLo : sRGBHi;
return sRGB;
}

static inline float SingleFromSRGB(float sRGBCol)
{
const float linearRGBLo = sRGBCol / 12.92f;
const float linearRGBHi = pow((sRGBCol + 0.055f) / 1.055f, 2.4f);
const float linearCol = (sRGBCol <= 0.04045f) ? linearRGBLo : linearRGBHi;
return linearCol;
}


static inline Color GammaToLinear(Color color)
{
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_movingfrostbite_to_pbr.pdf pg87
float<3> colorVec = { color.r, color.g, color.b };
float<3> linearRGBLo = { color.r / 12.92, color.g / 12.92, color.b / 12.92 };
float<3> linearRGBHi = {
pow((colorVec.x + 0.055) / 1.055, 2.4),
pow((colorVec.y + 0.055) / 1.055, 2.4),
pow((colorVec.z + 0.055) / 1.055, 2.4)
};
color.r = (color.r <= 0.04045) ? linearRGBLo.x : linearRGBHi.x,
color.g = (color.g <= 0.04045) ? linearRGBLo.y : linearRGBHi.y,
color.b = (color.b <= 0.04045) ? linearRGBLo.z : linearRGBHi.z;
color.r = SingleFromSRGB(color.r);
color.g = SingleFromSRGB(color.g);
color.b = SingleFromSRGB(color.b);
return color;
}

static inline Color LinearToGamma(Color color)
{
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_movingfrostbite_to_pbr.pdf pg87
float<3> colorVec = { color.r, color.g, color.b };
float<3> sRGBLo = { color.r * 12.92, color.g * 12.92, color.b * 12.92 };
float<3> sRGBHi = {
(pow(abs(colorVec.x), 1.0 / 2.4) * 1.055) - 0.055,
(pow(abs(colorVec.y), 1.0 / 2.4) * 1.055) - 0.055,
(pow(abs(colorVec.z), 1.0 / 2.4) * 1.055) - 0.055
};
color.r = (color.r <= 0.0031308) ? sRGBLo.x : sRGBHi.x,
color.g = (color.g <= 0.0031308) ? sRGBLo.y : sRGBHi.y,
color.b = (color.b <= 0.0031308) ? sRGBLo.z : sRGBHi.z;
color.r = SingleToSRGB(color.r);
color.g = SingleToSRGB(color.g);
color.b = SingleToSRGB(color.b);
return color;
}

Expand Down
57 changes: 36 additions & 21 deletions src/image/private/color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,30 @@ namespace Image
namespace
{
// http://ploobs.com.br/arquivos/1499
Math::Vec3 hue(float h)
Math::Vec3 Hue(float h)
{
float r = std::abs(h * 6.0f - 3.0f) - 1.0f;
float g = 2.0f - std::abs(h * 6.0f - 2.0f);
float b = 2.0f - std::abs(h * 6.0f - 4.0f);
return Math::Vec3(Core::Clamp(r, 0.0f, 1.0f), Core::Clamp(g, 0.0f, 1.0f), Core::Clamp(b, 0.0f, 1.0f));
}

// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf pg87
f32 SingleToSRGB(f32 linearCol)
{
const f32 sRGBLo = linearCol * 12.92f;
const f32 sRGBHi = (std::powf(std::abs(linearCol), 1.0f / 2.4f) * 1.055f) - 0.055f;
const f32 sRGB = (linearCol <= 0.0031308f) ? sRGBLo : sRGBHi;
return sRGB;
}

f32 SingleFromSRGB(f32 sRGBCol)
{
const f32 linearRGBLo = sRGBCol / 12.92f;
const f32 linearRGBHi = std::powf((sRGBCol + 0.055f) / 1.055f, 2.4f);
const f32 linearCol = (sRGBCol <= 0.04045f) ? linearRGBLo : linearRGBHi;
return linearCol;
}
}


Expand All @@ -28,7 +45,7 @@ namespace Image
{
}

HSVColor::HSVColor(f32* val)
HSVColor::HSVColor(const f32* val)
: h(val[0])
, s(val[1])
, v(val[2])
Expand All @@ -49,7 +66,7 @@ namespace Image
{
}

YCoCgColor::YCoCgColor(f32* val)
YCoCgColor::YCoCgColor(const f32* val)
: y(val[0])
, co(val[1])
, cg(val[2])
Expand All @@ -71,7 +88,7 @@ namespace Image
{
}

SRGBAColor::SRGBAColor(u8* val)
SRGBAColor::SRGBAColor(const u8* val)
: r(val[0])
, g(val[1])
, b(val[2])
Expand All @@ -96,7 +113,7 @@ namespace Image
{
}

RGBAColor::RGBAColor(f32* val)
RGBAColor::RGBAColor(const f32* val)
: r(val[0])
, g(val[1])
, b(val[2])
Expand Down Expand Up @@ -147,13 +164,12 @@ namespace Image

SRGBAColor ToSRGBA(RGBAColor rgba)
{
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf pg87
Math::Vec3 sRGBLo(rgba.r * 12.92f, rgba.g * 12.92f, rgba.b * 12.92f);
Math::Vec3 sRGBHi(std::pow(std::abs(rgba.r), 1.0f / 2.4f), std::pow(std::abs(rgba.g), 1.0f / 2.4f),
std::pow(std::abs(rgba.b), 1.0f / 2.4f));
sRGBHi = (sRGBHi * 1.055f) - Math::Vec3(0.055f, 0.055f, 0.055f);
RGBAColor sRGBA = RGBAColor((rgba.r <= 0.0031308) ? sRGBLo.x : sRGBHi.x,
(rgba.g <= 0.0031308f) ? sRGBLo.y : sRGBHi.y, (rgba.b <= 0.0031308f) ? sRGBLo.z : sRGBHi.z, rgba.a);
RGBAColor sRGBA = {
SingleToSRGB(rgba.r),
SingleToSRGB(rgba.g),
SingleToSRGB(rgba.b),
rgba.a,
};
sRGBA *= 255.0f;
sRGBA.r = std::roundf(sRGBA.r);
sRGBA.g = std::roundf(sRGBA.g);
Expand All @@ -166,7 +182,7 @@ namespace Image
RGBAColor ToRGB(HSVColor hsv)
{
const auto ONE = Math::Vec3(1.0f, 1.0f, 1.0f);
Math::Vec3 rgb = ((hue(hsv.h) - ONE) * hsv.s + ONE) * hsv.v;
Math::Vec3 rgb = ((Hue(hsv.h) - ONE) * hsv.s + ONE) * hsv.v;
return RGBAColor(rgb.x, rgb.y, rgb.z, 1.0f);
}

Expand All @@ -178,14 +194,13 @@ namespace Image

RGBAColor ToRGBA(SRGBAColor rgba)
{
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf pg87
Math::Vec3 linearRGBLo(rgba.r / 12.92f, rgba.g / 12.92f, rgba.b / 12.92f);
Math::Vec3 linearRGBHi(std::pow(((rgba.r / 255.0f) + 0.055f) / 1.055f, 2.4f),
std::pow(((rgba.g / 255.0f) + 0.055f) / 1.055f, 2.4f),
std::pow(((rgba.b / 255.0f) + 0.055f) / 1.055f, 2.4f));
return RGBAColor((rgba.r <= (255 * 0.04045)) ? linearRGBLo.x : linearRGBHi.x,
(rgba.g <= (255 * 0.04045)) ? linearRGBLo.y : linearRGBHi.y,
(rgba.b <= (255 * 0.04045)) ? linearRGBLo.z : linearRGBHi.z, rgba.a / 255.0f);
RGBAColor sRGBA = {
SingleFromSRGB((f32)rgba.r / 255.0f),
SingleFromSRGB((f32)rgba.g / 255.0f),
SingleFromSRGB((f32)rgba.b / 255.0f),
(f32)rgba.a / 255.0f,
};
return sRGBA;
}

} // namespace Image
38 changes: 38 additions & 0 deletions src/image/private/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -862,4 +862,42 @@ namespace Image
}


bool ProcessTexelsCommon(Image& output, const Image& input, ProcessFn<void> processFn)
{
if(!SetupOutput(output, input, input.GetFormat()))
return false;

if(output.GetFormat() != input.GetFormat())
return false;

auto formatInfo = GPU::GetFormatInfo(input.GetFormat());
i32 size = formatInfo.blockBits_ / 8;

i32 levelW = input.GetWidth() / formatInfo.blockW_;
i32 levelH = input.GetHeight() / formatInfo.blockH_;

// Now the rest in the chain.
for(i32 level = 0; level < output.GetLevels() - 1; ++level)
{
u8* outputData = output.GetMipData<u8>(level);
const u8* inputData = input.GetMipData<u8>(level);

for(i32 y = 0; y < levelH; ++y)
{
i32 idx = (y * levelW) * size;
for(i32 x = 0; x < levelW; ++x)
{
processFn(&outputData[idx], &inputData[idx]);

idx += size;
}
}

levelW = Core::Max(levelW >> 1, 1);
levelH = Core::Max(levelH >> 1, 1);
}

return true;
}

} // namespace Image
25 changes: 25 additions & 0 deletions src/image/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ namespace Image
static const f32 INFINITE_PSNR = 99999.0f;
static const RGBAColor INFINITE_PSNR_RGBA = RGBAColor(INFINITE_PSNR, INFINITE_PSNR, INFINITE_PSNR, INFINITE_PSNR);

/**
* Process functions.
*/
template<typename TYPE>
using ProcessFn = Core::Function<void(TYPE*, const TYPE*)>;

/**
* Quality for conversion.
*/
Expand Down Expand Up @@ -70,4 +76,23 @@ namespace Image
*/
IMAGE_DLL RGBAColor CalculatePSNR(const Image& base, const Image& compare);

/**
* Process Texels.
* @a output will be created if not provided.
* @param output Output image.
* @param input Input image.
* @param processFn Function to call to process texels. This will be 1 block.
* @pre @a output and @a input formats match.
* @return success.
*/
template<typename TYPE>
bool ProcessTexels(Image& output, const Image& input, ProcessFn<TYPE> processFn)
{
return ProcessTexelsCommon(
output, input, [&processFn](void* o, const void* i) { processFn((TYPE*)o, (const TYPE*)i); });
}

IMAGE_DLL bool ProcessTexelsCommon(Image& output, const Image& input, ProcessFn<void> processFn);


} // namespace Image
39 changes: 33 additions & 6 deletions src/image/tests/color_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "image/color.h"
#include "core/random.h"
#include "core/vector.h"

#include "catch.hpp"

Expand All @@ -23,16 +25,39 @@ namespace
Image::RGBAColor(0.8f, 0.8f, 0.8f, 1.0f),
Image::RGBAColor(1.0f, 1.0f, 1.0f, 1.0f),
};

Core::Vector<Image::RGBAColor> GetTestColors()
{
Core::Vector<Image::RGBAColor> outColors;
Core::Random rng;

for(const auto rgba : testNormalizedRGB)
{
outColors.push_back(rgba);
}

for(i32 i = 0; i < 128; ++i)
{
f32 r = ((u32)rng.Generate() & 0xff) / 255.0f;
f32 g = ((u32)rng.Generate() & 0xff) / 255.0f;
f32 b = ((u32)rng.Generate() & 0xff) / 255.0f;
f32 a = ((u32)rng.Generate() & 0xff) / 255.0f;
outColors.push_back(Image::RGBAColor(r, g, b, a));
}

return outColors;
}
}

TEST_CASE("image-color-tests-hsv")
{
for(const auto rgbA : testNormalizedRGB)
Core::Vector<Image::RGBAColor> outColors = GetTestColors();
for(const auto rgbA : outColors)
{
Image::HSVColor hsv = Image::ToHSV(rgbA);
Image::RGBAColor rgbB = Image::ToRGB(hsv);

Core::Log("RGB(%.1f, %.1f, %.1f) -> HSV(%.1f, %.1f, %.1f) -> RGB(%.1f, %.1f, %.1f)\n", rgbA.r, rgbA.g, rgbA.b,
Core::Log("RGB(%.4f, %.4f, %.4f) -> HSV(%.4f, %.4f, %.4f) -> RGB(%.4f, %.4f, %.4f)\n", rgbA.r, rgbA.g, rgbA.b,
hsv.h, hsv.s, hsv.v, rgbB.r, rgbB.g, rgbB.b);

CHECK(EpsilonCompare(rgbA.r, rgbB.r, MAX_RGBA_ERROR));
Expand All @@ -43,12 +68,13 @@ TEST_CASE("image-color-tests-hsv")

TEST_CASE("image-color-tests-ycocg")
{
for(const auto rgbA : testNormalizedRGB)
Core::Vector<Image::RGBAColor> outColors = GetTestColors();
for(const auto rgbA : outColors)
{
Image::YCoCgColor ycocg = Image::ToYCoCg(rgbA);
Image::RGBAColor rgbB = Image::ToRGB(ycocg);

Core::Log("RGB(%.1f, %.1f, %.1f) -> YCoCg(%.1f, %.1f, %.1f) -> RGB(%.1f, %.1f, %.1f)\n", rgbA.r, rgbA.g, rgbA.b,
Core::Log("RGB(%.4f, %.4f, %.4f) -> YCoCg(%.4f, %.4f, %.4f) -> RGB(%.4f, %.4f, %.4f)\n", rgbA.r, rgbA.g, rgbA.b,
ycocg.y, ycocg.co, ycocg.cg, rgbB.r, rgbB.g, rgbB.b);


Expand All @@ -60,12 +86,13 @@ TEST_CASE("image-color-tests-ycocg")

TEST_CASE("image-color-tests-srgb")
{
for(const auto rgbA : testNormalizedRGB)
Core::Vector<Image::RGBAColor> outColors = GetTestColors();
for(const auto rgbA : outColors)
{
Image::SRGBAColor srgb = Image::ToSRGBA(rgbA);
Image::RGBAColor rgbB = Image::ToRGBA(srgb);

Core::Log("RGB(%.1f, %.1f, %.1f) -> SRGB(%.1f, %.1f, %.1f) -> RGB(%.1f, %.1f, %.1f)\n", rgbA.r, rgbA.g, rgbA.b,
Core::Log("RGB(%.4f, %.4f, %.4f) -> SRGB(%.4f, %.4f, %.4f) -> RGB(%.4f, %.4f, %.4f)\n", rgbA.r, rgbA.g, rgbA.b,
srgb.r / 255.0f, srgb.g / 255.0f, srgb.b / 255.0f, rgbB.r, rgbB.g, rgbB.b);


Expand Down
Loading

0 comments on commit 622f691

Please sign in to comment.