Merge pull request #11 from DocHoncho/issue-295-dev

Re-implement nearest-neighbor interpolation
This commit is contained in:
David Capello 2013-12-29 12:28:39 -08:00
commit ab42d38947
2 changed files with 125 additions and 15 deletions

View File

@ -35,23 +35,22 @@ void resize_image(const Image* src, Image* dst, ResizeMethod method, const Palet
switch (method) {
// TODO optimize this
case RESIZE_METHOD_NEAREST_NEIGHBOR: {
uint32_t color;
double u, v, du, dv;
int x, y;
case RESIZE_METHOD_NEAREST_NEIGHBOR:
{
int o_width = src->getWidth(), o_height = src->getHeight();
int n_width = dst->getWidth(), n_height = dst->getHeight();
double x_ratio = o_width / (double)n_width;
double y_ratio = o_height / (double)n_height;
double px, py;
int i;
u = v = 0.0;
du = src->getWidth() * 1.0 / dst->getWidth();
dv = src->getHeight() * 1.0 / dst->getHeight();
for (y=0; y<dst->getHeight(); ++y) {
for (x=0; x<dst->getWidth(); ++x) {
color = src->getPixel(MID(0, u, src->getWidth()-1),
MID(0, v, src->getHeight()-1));
dst->putPixel(x, y, color);
u += du;
for (int y = 0; y < n_height; y++) {
for (int x = 0; x < n_width; x++) {
px = floor(x * x_ratio);
py = floor(y * y_ratio);
i = (int)(py * o_width + px);
dst->putPixel(x, y, src->getPixel(i % o_width, i / o_width));
}
u = 0.0;
v += dv;
}
break;
}

View File

@ -0,0 +1,111 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2013 David Capello
//
// This source file is distributed under MIT license,
// please read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtest/gtest.h>
#include "raster/color.h"
#include "raster/image.h"
#include "raster/algorithm/resize_image.h"
using namespace std;
using namespace raster;
/***************************
* Test dat
*/
// Base image
color_t test_image_base_3x3[9] =
{
0x000000, 0xffffff, 0x000000,
0xffffff, 0xffffff, 0xffffff,
0x000000, 0xffffff, 0x000000
};
// Base image scaled to 9x9 with nearest neighbor interpolation
color_t test_image_scaled_9x9_nearest[81] =
{
0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000
};
// Base image scalled to 9x9 with bilinear interpolation
color_t test_image_scaled_9x9_bilinear[81] =
{
0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000,
0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000,
0x565656, 0x565656, 0x8f8f8f, 0xc6c6c6, 0xffffff, 0xc6c6c6, 0x8f8f8f, 0x565656, 0x565656,
0xa9a9a9, 0xa9a9a9, 0xc6c6c6, 0xe2e2e2, 0xffffff, 0xe2e2e2, 0xc6c6c6, 0xa9a9a9, 0xa9a9a9,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0xa9a9a9, 0xa9a9a9, 0xc6c6c6, 0xe2e2e2, 0xffffff, 0xe2e2e2, 0xc6c6c6, 0xa9a9a9, 0xa9a9a9,
0x565656, 0x565656, 0x8f8f8f, 0xc6c6c6, 0xffffff, 0xc6c6c6, 0x8f8f8f, 0x565656, 0x565656,
0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000,
0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000
};
Image* create_image_from_data(PixelFormat format, color_t* data, int width, int height)
{
Image* new_image = Image::create(format, width, height);
for (int i = 0; i < width * height; i++) {
new_image->putPixel(i % width, i / width, data[i]);
}
return new_image;
}
// Simple pixel to pixel image comparison
bool compare_images(Image* a, Image* b)
{
for (int y = 0; y < a->getHeight(); y++) {
for (int x = 0; x < a->getWidth(); x++) {
if (!(a->getPixel(x, y) == b->getPixel(x, y)))
return false;
}
}
return true;
}
TEST(ResizeImage, NearestNeighborInterp)
{
Image* src = create_image_from_data(IMAGE_RGB, test_image_base_3x3, 3, 3);
Image* dst = Image::create(IMAGE_RGB, 9, 9);
// Pre-rendered test image for comparison
Image* test_dst = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_nearest, 9, 9);
algorithm::resize_image(src, dst, algorithm::ResizeMethod::RESIZE_METHOD_NEAREST_NEIGHBOR, NULL, NULL);
ASSERT_TRUE(compare_images(dst, test_dst)) << "resize_image() result does not match test image!";
}
TEST(ResizeImage, BilinearInterpRGBType)
{
Image* src = create_image_from_data(IMAGE_RGB, test_image_base_3x3, 3, 3);
Image* dst = Image::create(IMAGE_RGB, 9, 9);
// Pre-rendered test image for comparison
Image* test_dst = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_bilinear, 9, 9);
algorithm::resize_image(src, dst, algorithm::ResizeMethod::RESIZE_METHOD_BILINEAR, NULL, NULL);
ASSERT_TRUE(compare_images(dst, test_dst)) << "resize_image() result does not match test image!";
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}