diff --git a/Base/include/Image.h b/Base/include/Image.h index 0b56aed..ab9c974 100644 --- a/Base/include/Image.h +++ b/Base/include/Image.h @@ -107,6 +107,9 @@ namespace FasTC { double ComputePSNR(Image *other); double ComputeSSIM(Image *other); + + double ComputeEntropy(); + double ComputeMeanLocalEntropy(); // Function to allow derived classes to populate the pixel array. // This may involve decompressing a compressed image or otherwise diff --git a/Base/src/Image.cpp b/Base/src/Image.cpp index 2f913a2..bc44449 100644 --- a/Base/src/Image.cpp +++ b/Base/src/Image.cpp @@ -406,6 +406,62 @@ double Image::ComputeSSIM(Image *other) { return mssim / static_cast(w * h); } +template +double Image::ComputeMeanLocalEntropy() { + const uint32 kKernelSz = 15; + const uint32 kHalfKernelSz = kKernelSz / 2; + Image entropyIdx(GetWidth() - kKernelSz + 1, GetHeight() - kKernelSz + 1); + for(uint32 j = kHalfKernelSz; j < GetHeight() - kHalfKernelSz; j++) { + for(uint32 i = kHalfKernelSz; i < GetWidth() - kHalfKernelSz; i++) { + + Image subImg(kKernelSz, kKernelSz); + for(uint32 y = 0; y < kKernelSz; y++) + for(uint32 x = 0; x < kKernelSz; x++) { + subImg(x, y) = (*this)(i - kHalfKernelSz + x, j - kHalfKernelSz + y); + } + entropyIdx(i-kHalfKernelSz, j-kHalfKernelSz) = + static_cast(subImg.ComputeEntropy()); + } + } + + double sum = 0; + for(uint32 j = 0; j < entropyIdx.GetHeight(); j++) + for(uint32 i = 0; i < entropyIdx.GetWidth(); i++) { + sum += static_cast(entropyIdx(i, j)); + } + return sum / (entropyIdx.GetHeight() * entropyIdx.GetWidth()); +} + +template +double Image::ComputeEntropy() { + uint32 hist[256]; + memset(hist, 0, sizeof(hist)); + + ComputePixels(); + + Image intensity(GetWidth(), GetHeight()); + ConvertTo(intensity); + + for(uint32 j = 0; j < GetHeight(); j++) { + for(uint32 i = 0; i < GetWidth(); i++) { + float iflt = static_cast(intensity(i, j)); + uint32 iv = static_cast(iflt * 255.0f + 0.5f); + assert(iv < 256); + + hist[iv]++; + } + } + + double ret = 0; + for(uint32 i = 0; i < 256; i++) { + if(hist[i] > 0) { + float p = static_cast(hist[i]) / static_cast(GetHeight() * GetWidth()); + ret += p * log2(p); + } + } + return -ret; +} + // !FIXME! These won't work for non-RGBA8 data. template void Image::ConvertToBlockStreamOrder() {