mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2025-01-08 22:05:37 +00:00
Add filtering operation.
This commit is contained in:
parent
076ca07bcf
commit
72697f650c
|
@ -49,6 +49,8 @@
|
||||||
|
|
||||||
namespace FasTC {
|
namespace FasTC {
|
||||||
|
|
||||||
|
class IPixel;
|
||||||
|
|
||||||
template<typename U, typename V>
|
template<typename U, typename V>
|
||||||
extern double ComputePSNR(Image<U> *img1, Image<V> *img2);
|
extern double ComputePSNR(Image<U> *img1, Image<V> *img2);
|
||||||
|
|
||||||
|
@ -105,6 +107,11 @@ namespace FasTC {
|
||||||
// appropriate pixels.
|
// appropriate pixels.
|
||||||
virtual void ComputePixels() { }
|
virtual void ComputePixels() { }
|
||||||
|
|
||||||
|
// Filters the image with a given set of kernel values. The values
|
||||||
|
// are normalized before they are used (i.e. we make sure that they
|
||||||
|
// sum up to one).
|
||||||
|
void Filter(const Image<IPixel> &kernel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32 m_Width;
|
uint32 m_Width;
|
||||||
uint32 m_Height;
|
uint32 m_Height;
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -289,6 +290,64 @@ void Image<PixelType>::SetImageData(uint32 width, uint32 height, PixelType *data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline T Clamp(const T &v, const T &a, const T &b) {
|
||||||
|
return ::std::min(::std::max(a, v), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename PixelType>
|
||||||
|
void Image<PixelType>::Filter(const Image<IPixel> &kernel) {
|
||||||
|
Image<IPixel> k(kernel);
|
||||||
|
|
||||||
|
// Only odd sized filters make sense....
|
||||||
|
assert(k.GetWidth() % 2);
|
||||||
|
assert(k.GetHeight() % 2);
|
||||||
|
|
||||||
|
double sum = 0.0;
|
||||||
|
for(uint32 j = 0; j < k.GetHeight(); j++) {
|
||||||
|
for(uint32 i = 0; i < k.GetWidth(); i++) {
|
||||||
|
sum += static_cast<float>(k(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32 j = 0; j < k.GetHeight(); j++) {
|
||||||
|
for(uint32 i = 0; i < k.GetWidth(); i++) {
|
||||||
|
k(i, j) = static_cast<float>(k(i, j)) / sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 ih = static_cast<int32>(GetHeight());
|
||||||
|
int32 iw = static_cast<int32>(GetWidth());
|
||||||
|
|
||||||
|
int32 kh = static_cast<int32>(k.GetHeight());
|
||||||
|
int32 kw = static_cast<int32>(k.GetWidth());
|
||||||
|
|
||||||
|
Image<PixelType> filtered(iw, ih);
|
||||||
|
|
||||||
|
for(int32 j = 0; j < ih; j++) {
|
||||||
|
for(int32 i = 0; i < iw; i++) {
|
||||||
|
int32 yoffset = j - (k.GetHeight() / 2);
|
||||||
|
int32 xoffset = i - (k.GetWidth() / 2);
|
||||||
|
|
||||||
|
Color newPixel;
|
||||||
|
for(int32 y = 0; y < kh; y++) {
|
||||||
|
for(int32 x = 0; x < kw; x++) {
|
||||||
|
PixelType pixel = ((*this)(
|
||||||
|
Clamp<int32>(x + xoffset, 0, GetWidth() - 1),
|
||||||
|
Clamp<int32>(y + yoffset, 0, GetHeight() - 1)));
|
||||||
|
Color c; c.Unpack(pixel.Pack());
|
||||||
|
Color scaled = c * static_cast<float>(k(x, y));
|
||||||
|
newPixel += scaled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered(i, j).Unpack(newPixel.Pack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*this = filtered;
|
||||||
|
}
|
||||||
|
|
||||||
template class Image<Pixel>;
|
template class Image<Pixel>;
|
||||||
template class Image<IPixel>;
|
template class Image<IPixel>;
|
||||||
template class Image<Color>;
|
template class Image<Color>;
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
#include "IPixel.h"
|
||||||
#include "Pixel.h"
|
#include "Pixel.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
|
@ -119,3 +120,32 @@ TEST(Image, AssignmentOperator) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Image, Filter) {
|
||||||
|
const uint32 w = 16;
|
||||||
|
const uint32 h = 16;
|
||||||
|
|
||||||
|
// Make a black and white image...
|
||||||
|
FasTC::Image<FasTC::IPixel> img(w, h);
|
||||||
|
for(uint32 j = 0; j < h; j++) {
|
||||||
|
for(uint32 i = 0; i < w; i++) {
|
||||||
|
if((i ^ j) % 2)
|
||||||
|
img(i, j) = 1.0f;
|
||||||
|
else
|
||||||
|
img(i, j) = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a weird averaging kernel...
|
||||||
|
FasTC::Image<FasTC::IPixel> kernel(3, 3);
|
||||||
|
kernel(0, 1) = kernel(1, 0) = kernel(1, 2) = kernel(2, 1) = 0.125f;
|
||||||
|
kernel(1, 1) = 0.5f;
|
||||||
|
|
||||||
|
img.Filter(kernel);
|
||||||
|
|
||||||
|
for(uint32 j = 1; j < h-1; j++) {
|
||||||
|
for(uint32 i = 1; i < w-1; i++) {
|
||||||
|
EXPECT_NEAR(static_cast<float>(img(i, j)), 0.5f, 0.01);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue