From c59e4db15a87448b109f4aca4147f3e59e5bba39 Mon Sep 17 00:00:00 2001 From: castano Date: Sat, 27 Sep 2008 07:32:11 +0000 Subject: [PATCH] Implement general scale filter, including upsampling --- ChangeLog | 1 + src/nvimage/Filter.cpp | 16 +++++++---- src/nvimage/FloatImage.cpp | 59 ++------------------------------------ src/nvimage/FloatImage.h | 2 +- src/nvtt/Compressor.cpp | 2 +- src/nvtt/tools/resize.cpp | 24 ++++++++++++---- 6 files changed, 35 insertions(+), 69 deletions(-) diff --git a/ChangeLog b/ChangeLog index 664b324..af911c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ NVIDIA Texture Tools version 2.0.4 * Fix error in RGB format output; reported by jonsoh. See issue 49. * Added support RGB format dithering by jonsoh. Fixes issue 50 and 51. * Prevent infinite loop in indexMirror when width equal 1. Fixes issue 65. + * Implement general scale filter, including upsampling. NVIDIA Texture Tools version 2.0.3 * More accurate DXT3 compressor. Fixes issue 38. diff --git a/src/nvimage/Filter.cpp b/src/nvimage/Filter.cpp index f72388a..1b60b8c 100644 --- a/src/nvimage/Filter.cpp +++ b/src/nvimage/Filter.cpp @@ -26,10 +26,10 @@ * http://www.xmission.com/~legalize/zoom.html * * Reconstruction Filters in Computer Graphics - * http://www.mentallandscape.com/Papers_siggraph88.pdf + * http://www.mentallandscape.com/Papers_siggraph88.pdf * * More references: - * http://www.worldserver.com/turk/computergraphics/ResamplingFilters.pdf + * http://www.worldserver.com/turk/computergraphics/ResamplingFilters.pdf * http://www.dspguide.com/ch16.htm */ @@ -541,12 +541,17 @@ void Kernel2::initBlendedSobel(const Vector4 & scale) PolyphaseKernel::PolyphaseKernel(const Filter & f, uint srcLength, uint dstLength, int samples/*= 32*/) { - nvCheck(srcLength >= dstLength); // @@ Upsampling not implemented! nvDebugCheck(samples > 0); - - const float scale = float(dstLength) / float(srcLength); + + float scale = float(dstLength) / float(srcLength); const float iscale = 1.0f / scale; + if (scale > 1) { + // Upsampling. + samples = 1; + scale = 1; + } + m_length = dstLength; m_width = f.width() * iscale; m_windowSize = (int)ceilf(m_width * 2) + 1; @@ -577,6 +582,7 @@ PolyphaseKernel::PolyphaseKernel(const Filter & f, uint srcLength, uint dstLengt m_data[i * m_windowSize + j] /= total; } } + } PolyphaseKernel::~PolyphaseKernel() diff --git a/src/nvimage/FloatImage.cpp b/src/nvimage/FloatImage.cpp index baa99dd..e16ae35 100644 --- a/src/nvimage/FloatImage.cpp +++ b/src/nvimage/FloatImage.cpp @@ -540,73 +540,18 @@ FloatImage * FloatImage::fastDownSample() const return dst_image.release(); } -/* -/// Downsample applying a 1D kernel separately in each dimension. -FloatImage * FloatImage::downSample(const Kernel1 & kernel, WrapMode wm) const -{ - const uint w = max(1, m_width / 2); - const uint h = max(1, m_height / 2); - - return downSample(kernel, w, h, wm); -} - - -/// Downsample applying a 1D kernel separately in each dimension. -FloatImage * FloatImage::downSample(const Kernel1 & kernel, uint w, uint h, WrapMode wm) const -{ - nvCheck(!(kernel.windowSize() & 1)); // Make sure that kernel m_width is even. - - AutoPtr tmp_image( new FloatImage() ); - tmp_image->allocate(m_componentNum, w, m_height); - - AutoPtr dst_image( new FloatImage() ); - dst_image->allocate(m_componentNum, w, h); - - const float xscale = float(m_width) / float(w); - const float yscale = float(m_height) / float(h); - - for(uint c = 0; c < m_componentNum; c++) { - float * tmp_channel = tmp_image->channel(c); - - for(uint y = 0; y < m_height; y++) { - for(uint x = 0; x < w; x++) { - - float sum = this->applyKernelHorizontal(&kernel, uint(x*xscale), y, c, wm); - - const uint tmp_index = tmp_image->index(x, y); - tmp_channel[tmp_index] = sum; - } - } - - float * dst_channel = dst_image->channel(c); - - for(uint y = 0; y < h; y++) { - for(uint x = 0; x < w; x++) { - - float sum = tmp_image->applyKernelVertical(&kernel, uint(x*xscale), uint(y*yscale), c, wm); - - const uint dst_index = dst_image->index(x, y); - dst_channel[dst_index] = sum; - } - } - } - - return dst_image.release(); -} -*/ - /// Downsample applying a 1D kernel separately in each dimension. FloatImage * FloatImage::downSample(const Filter & filter, WrapMode wm) const { const uint w = max(1, m_width / 2); const uint h = max(1, m_height / 2); - return downSample(filter, w, h, wm); + return resize(filter, w, h, wm); } /// Downsample applying a 1D kernel separately in each dimension. -FloatImage * FloatImage::downSample(const Filter & filter, uint w, uint h, WrapMode wm) const +FloatImage * FloatImage::resize(const Filter & filter, uint w, uint h, WrapMode wm) const { // @@ Use monophase filters when frac(m_width / w) == 0 diff --git a/src/nvimage/FloatImage.h b/src/nvimage/FloatImage.h index 20fa468..74e7537 100644 --- a/src/nvimage/FloatImage.h +++ b/src/nvimage/FloatImage.h @@ -63,7 +63,7 @@ public: NVIMAGE_API FloatImage * fastDownSample() const; NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm) const; - NVIMAGE_API FloatImage * downSample(const Filter & filter, uint w, uint h, WrapMode wm) const; + NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm) const; //NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, WrapMode wm) const; //NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, uint w, uint h, WrapMode wm) const; diff --git a/src/nvtt/Compressor.cpp b/src/nvtt/Compressor.cpp index a4eb3e0..d070d77 100644 --- a/src/nvtt/Compressor.cpp +++ b/src/nvtt/Compressor.cpp @@ -571,7 +571,7 @@ void Compressor::Private::scaleMipmap(Mipmap & mipmap, const InputOptions::Priva // Resize image. BoxFilter boxFilter; - mipmap.setImage(mipmap.asFloatImage()->downSample(boxFilter, w, h, (FloatImage::WrapMode)inputOptions.wrapMode)); + mipmap.setImage(mipmap.asFloatImage()->resize(boxFilter, w, h, (FloatImage::WrapMode)inputOptions.wrapMode)); } diff --git a/src/nvtt/tools/resize.cpp b/src/nvtt/tools/resize.cpp index c8b8deb..df2fc10 100644 --- a/src/nvtt/tools/resize.cpp +++ b/src/nvtt/tools/resize.cpp @@ -73,10 +73,12 @@ int main(int argc, char *argv[]) float scale = 0.5f; float gamma = 2.2f; - nv::Filter * filter = NULL; + nv::AutoPtr filter; nv::Path input; nv::Path output; + nv::FloatImage::WrapMode wrapMode = nv::FloatImage::WrapMode_Mirror; + // Parse arguments. for (int i = 1; i < argc; i++) { @@ -108,9 +110,18 @@ int main(int argc, char *argv[]) else if (strcmp("lanczos", argv[i]) == 0) filter = new nv::LanczosFilter(); else if (strcmp("kaiser", argv[i]) == 0) { filter = new nv::KaiserFilter(3); - ((nv::KaiserFilter *)filter)->setParameters(4.0f, 1.0f); + ((nv::KaiserFilter *)filter.ptr())->setParameters(4.0f, 1.0f); } } + else if (strcmp("-f", argv[i]) == 0) + { + if (i+1 == argc) break; + i++; + + if (strcmp("mirror", argv[i]) == 0) wrapMode = nv::FloatImage::WrapMode_Mirror; + else if (strcmp("repeat", argv[i]) == 0) wrapMode = nv::FloatImage::WrapMode_Repeat; + else if (strcmp("clamp", argv[i]) == 0) wrapMode = nv::FloatImage::WrapMode_Clamp; + } else if (argv[i][0] != '-') { input = argv[i]; @@ -140,6 +151,10 @@ int main(int argc, char *argv[]) printf(" * mitchell\n"); printf(" * lanczos\n"); printf(" * kaiser\n"); + printf(" -w mode One of the following: (default = 'mirror')\n"); + printf(" * mirror\n"); + printf(" * repeat\n"); + printf(" * clamp\n"); return 1; } @@ -155,15 +170,14 @@ int main(int argc, char *argv[]) nv::FloatImage fimage(&image); fimage.toLinear(0, 3, gamma); - nv::AutoPtr fresult(fimage.downSample(*filter, uint(image.width() * scale), uint(image.height() * scale), nv::FloatImage::WrapMode_Mirror)); + nv::AutoPtr fresult(fimage.resize(*filter, uint(image.width() * scale), uint(image.height() * scale), wrapMode)); nv::AutoPtr result(fresult->createImageGammaCorrect(gamma)); + result->setFormat(nv::Image::Format_ARGB); nv::StdOutputStream stream(output); nv::ImageIO::saveTGA(stream, result.ptr()); // @@ Add generic save function. Add support for png too. - delete filter; - return 0; }