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 {
|
||||
|
||||
class IPixel;
|
||||
|
||||
template<typename U, typename V>
|
||||
extern double ComputePSNR(Image<U> *img1, Image<V> *img2);
|
||||
|
||||
|
@ -105,6 +107,11 @@ namespace FasTC {
|
|||
// appropriate pixels.
|
||||
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:
|
||||
uint32 m_Width;
|
||||
uint32 m_Height;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include "Image.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#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<IPixel>;
|
||||
template class Image<Color>;
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
#include "Image.h"
|
||||
#include "IPixel.h"
|
||||
#include "Pixel.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