diff --git a/Base/include/FasTC/Image.h b/Base/include/FasTC/Image.h index b09b6cb..2f1997b 100644 --- a/Base/include/FasTC/Image.h +++ b/Base/include/FasTC/Image.h @@ -97,6 +97,8 @@ namespace FasTC { double ComputePSNR(Image *other); double ComputeSSIM(Image *other); + Image Diff(Image *other); + double ComputeEntropy(); double ComputeMeanLocalEntropy(); diff --git a/Base/src/Image.cpp b/Base/src/Image.cpp index 8700517..405cb99 100644 --- a/Base/src/Image.cpp +++ b/Base/src/Image.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #define _USE_MATH_DEFINES #include @@ -66,6 +67,29 @@ static inline T Clamp(const T &v, const T &a, const T &b) { return ::std::min(::std::max(a, v), b); } +template inline T PixelAbs(const T &a); +template<> inline FasTC::IPixel PixelAbs(const FasTC::IPixel &p) { + return FasTC::IPixel(fabs(p[0])); +} + +template<> inline FasTC::Pixel PixelAbs(const FasTC::Pixel &p) { + FasTC::Pixel result = p; + if (result.R() < 0) { result.R() = -result.R(); } + if (result.G() < 0) { result.G() = -result.G(); } + if (result.B() < 0) { result.B() = -result.B(); } + if (result.A() < 0) { result.A() = -result.A(); } + return result; +} + +template<> inline FasTC::Color PixelAbs(const FasTC::Color &p) { + FasTC::Color result = p; + if (result.R() < 0) { result.R() = -result.R(); } + if (result.G() < 0) { result.G() = -result.G(); } + if (result.B() < 0) { result.B() = -result.B(); } + if (result.A() < 0) { result.A() = -result.A(); } + return result; +} + // wtf #ifdef _MSC_VER template T log2(T x) { return static_cast(log((long double)x) / log(2.0)); } @@ -174,6 +198,35 @@ const PixelType & Image::operator()(uint32 i, uint32 j) const { return m_Pixels[j * GetWidth() + i]; } +template +Image Image::Diff(Image *other) { + if (!other) { + std::cerr << "Image::Diff - ERROR: other == null" << std::endl; + assert(false); + } + + if (GetWidth() != other->GetWidth() || + GetHeight() != other->GetHeight()) { + std::cerr << "Image::Diff - ERROR: Images differ in dimension" << std::endl; + assert(false); + return *this; + } + + this->ComputePixels(); + other->ComputePixels(); + + Image result(GetWidth(), GetHeight()); + for (int j = 0; j < GetHeight(); ++j) { + for (int i = 0; i < GetWidth(); ++i) { + result(i, j) = PixelAbs((*this)(i, j) - (*other)(i, j)); + result(i, j).MakeOpaque(); + } + } + + // !SPEED! We do an unnecessary copy here... + return result; +} + template double Image::ComputePSNR(Image *other) { if(!other) diff --git a/CLTool/src/compare.cpp b/CLTool/src/compare.cpp index 4ed6f79..039cf7a 100644 --- a/CLTool/src/compare.cpp +++ b/CLTool/src/compare.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #ifdef _MSC_VER @@ -59,27 +60,67 @@ #include "FasTC/TexComp.h" #include "FasTC/ThreadSafeStreambuf.h" +static void PrintUsageAndExit() { + fprintf(stderr, "Usage: compare [-d] \n"); + exit(1); +} + +void gen_random(char *s, const int len) { + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + srand(time(NULL)); + for (int i = 0; i < len; ++i) { + s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; + } + + s[len] = 0; +} + int main(int argc, char **argv) { - if(argc != 3) { - fprintf(stderr, "Usage: compare \n"); - return 1; + if(argc != 3 && argc != 4) { + PrintUsageAndExit(); } - ImageFile img1f (argv[1]); + bool diff_images = false; + int arg = 1; + if (strncmp(argv[arg], "-d", 2) == 0) { + diff_images = true; + arg++; + } + + ImageFile img1f (argv[arg]); if(!img1f.Load()) { - fprintf(stderr, "Error loading file: %s\n", argv[1]); + fprintf(stderr, "Error loading file: %s\n", argv[arg]); return 1; } + arg++; - ImageFile img2f (argv[2]); + ImageFile img2f (argv[arg]); if(!img2f.Load()) { - fprintf(stderr, "Error loading file: %s\n", argv[2]); + fprintf(stderr, "Error loading file: %s\n", argv[arg]); return 1; } + arg++; FasTC::Image<> &img1 = *img1f.GetImage(); FasTC::Image<> &img2 = *img2f.GetImage(); + if (diff_images) { + FasTC::Image<> diff = img1.Diff(&img2); + + char fname_buf [5 + 16 + 4]; // "diff-" + hash + ".png" + strncat(fname_buf, "diff-", 5); + gen_random(fname_buf + 5, 16); + strncat(fname_buf + 5 + 16, ".png", 4); + + EImageFileFormat fmt = ImageFile::DetectFileFormat(fname_buf); + ImageFile cImgFile (fname_buf, fmt, diff); + cImgFile.Write(); + } + double PSNR = img1.ComputePSNR(&img2); if(PSNR > 0.0) { fprintf(stdout, "PSNR: %.3f\n", PSNR);