Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add CLI option to set min/mag filters #271

Merged
merged 1 commit into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/tev/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,18 @@ void toggleConsole();
bool shuttingDown();
void setShuttingDown();

enum EInterpolationMode : int {
Nearest = 0,
Bilinear,
Trilinear,

// This enum value should never be used directly. It facilitates looping over all members of this enum.
NumInterpolationModes,
};

EInterpolationMode toInterpolationMode(std::string name);
std::string toString(EInterpolationMode mode);

enum ETonemap : int {
SRGB = 0,
Gamma,
Expand Down
7 changes: 4 additions & 3 deletions include/tev/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <tev/Box.h>
#include <tev/Channel.h>
#include <tev/Common.h>
#include <tev/SharedQueue.h>
#include <tev/ThreadPool.h>
#include <tev/VectorGraphics.h>
Expand Down Expand Up @@ -144,8 +145,7 @@ class Image {

bool isInterleavedRgba(const std::vector<std::string>& channelNames) const;

nanogui::Texture* texture(const std::string& channelGroupName);
nanogui::Texture* texture(const std::vector<std::string>& channelNames);
nanogui::Texture* texture(const std::vector<std::string>& channelNames, EInterpolationMode minFilter, EInterpolationMode magFilter);

std::vector<std::string> channelsInGroup(const std::string& groupName) const;
void decomposeChannelGroup(const std::string& groupName);
Expand Down Expand Up @@ -221,7 +221,8 @@ class Image {
int mId;
};

Task<std::vector<std::shared_ptr<Image>>> tryLoadImage(int imageId, fs::path path, std::istream& iStream, std::string channelSelector, bool applyGainmaps);
Task<std::vector<std::shared_ptr<Image>>>
tryLoadImage(int imageId, fs::path path, std::istream& iStream, std::string channelSelector, bool applyGainmaps);
Task<std::vector<std::shared_ptr<Image>>> tryLoadImage(fs::path path, std::istream& iStream, std::string channelSelector, bool applyGainmaps);
Task<std::vector<std::shared_ptr<Image>>> tryLoadImage(int imageId, fs::path path, std::string channelSelector, bool applyGainmaps);
Task<std::vector<std::shared_ptr<Image>>> tryLoadImage(fs::path path, std::string channelSelector, bool applyGainmaps);
Expand Down
10 changes: 10 additions & 0 deletions include/tev/ImageCanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#pragma once

#include <tev/Box.h>
#include <tev/Common.h>
#include <tev/Image.h>
#include <tev/Lazy.h>
#include <tev/UberShader.h>
Expand Down Expand Up @@ -98,6 +99,12 @@ class ImageCanvas : public nanogui::Canvas {
bool clipToLdr() const { return mClipToLdr; }
void setClipToLdr(bool value) { mClipToLdr = value; }

EInterpolationMode minFilter() const { return mMinFilter; }
void setMinFilter(EInterpolationMode value) { mMinFilter = value; }

EInterpolationMode magFilter() const { return mMagFilter; }
void setMagFilter(EInterpolationMode value) { mMagFilter = value; }

// The following functions return four values per pixel in RGBA order. The number of pixels is given by `imageDataSize()`. If the canvas
// does not currently hold an image, or no channels are displayed, then zero pixels are returned.
nanogui::Vector2i imageDataSize() const { return cropInImageCoords().size(); }
Expand Down Expand Up @@ -143,6 +150,9 @@ class ImageCanvas : public nanogui::Canvas {

bool mClipToLdr = false;

EInterpolationMode mMinFilter = EInterpolationMode::Trilinear;
EInterpolationMode mMagFilter = EInterpolationMode::Nearest;

std::shared_ptr<Image> mImage;
std::shared_ptr<Image> mReference;

Expand Down
6 changes: 6 additions & 0 deletions include/tev/ImageViewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ class ImageViewer : public nanogui::Screen {

void resetImage();

EInterpolationMode minFilter() const { return mImageCanvas->minFilter(); }
void setMinFilter(EInterpolationMode value) { mImageCanvas->setMinFilter(value); }

EInterpolationMode magFilter() const { return mImageCanvas->magFilter(); }
void setMagFilter(EInterpolationMode value) { mImageCanvas->setMagFilter(value); }

ETonemap tonemap() const { return mImageCanvas->tonemap(); }

void setTonemap(ETonemap tonemap);
Expand Down
23 changes: 23 additions & 0 deletions src/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,29 @@ bool shuttingDown() { return sShuttingDown; }

void setShuttingDown() { sShuttingDown = true; }

EInterpolationMode toInterpolationMode(string name) {
// Perform matching on uppercase strings
name = toUpper(name);
if (name == "NEAREST") {
return Nearest;
} else if (name == "BILINEAR") {
return Bilinear;
} else if (name == "TRILINEAR" || name == "FC") {
return Trilinear;
} else {
return Nearest;
}
}

string toString(EInterpolationMode mode) {
switch (mode) {
case Nearest: return "NEAREST";
case Bilinear: return "BILINEAR";
case Trilinear: return "TRILINEAR";
default: throw runtime_error{"Unknown interpolation mode."};
}
}

ETonemap toTonemap(string name) {
// Perform matching on uppercase strings
name = toUpper(name);
Expand Down
27 changes: 19 additions & 8 deletions src/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <tev/Common.h>
#include <tev/Image.h>
#include <tev/ThreadPool.h>
#include <tev/imageio/ImageLoader.h>
Expand Down Expand Up @@ -291,29 +292,36 @@ bool Image::isInterleavedRgba(const vector<string>& channelNames) const {
return interleavedData;
}

Texture* Image::texture(const string& channelGroupName) { return texture(channelsInGroup(channelGroupName)); }

Texture* Image::texture(const vector<string>& channelNames) {
string lookup = join(channelNames, ",");
Texture* Image::texture(const vector<string>& channelNames, EInterpolationMode minFilter, EInterpolationMode magFilter) {
string lookup = fmt::format("{}-{}-{}", join(channelNames, ","), tev::toString(minFilter), tev::toString(magFilter));
auto iter = mTextures.find(lookup);
if (iter != end(mTextures)) {
auto& texture = iter->second;
if (texture.mipmapDirty) {
if (texture.mipmapDirty && minFilter == EInterpolationMode::Trilinear) {
texture.nanoguiTexture->generate_mipmap();
texture.mipmapDirty = false;
}
return texture.nanoguiTexture.get();
}

const auto toNanogui = [](EInterpolationMode mode) {
switch (mode) {
case EInterpolationMode::Nearest: return Texture::InterpolationMode::Nearest;
case EInterpolationMode::Bilinear: return Texture::InterpolationMode::Bilinear;
case EInterpolationMode::Trilinear: return Texture::InterpolationMode::Trilinear;
default: throw runtime_error{"Unknown interpolation mode."};
}
};

mTextures.emplace(
lookup,
ImageTexture{
new Texture{
Texture::PixelFormat::RGBA,
Texture::ComponentFormat::Float32,
{size().x(), size().y()},
Texture::InterpolationMode::Trilinear,
Texture::InterpolationMode::Nearest,
toNanogui(minFilter),
toNanogui(magFilter),
Texture::WrapMode::ClampToEdge,
1, Texture::TextureFlags::ShaderRead,
true, },
Expand Down Expand Up @@ -354,7 +362,10 @@ Texture* Image::texture(const vector<string>& channelNames) {
texture->upload((uint8_t*)data.data());
}

texture->generate_mipmap();
if (minFilter == EInterpolationMode::Trilinear) {
texture->generate_mipmap();
}

return texture.get();
}

Expand Down
6 changes: 3 additions & 3 deletions src/ImageCanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void ImageCanvas::draw_contents() {
2.0f * inverse(Vector2f{m_size}) / mPixelRatio,
Vector2f{20.0f},
!mSupportsHdr,
image->texture(mImage->channelsInGroup(mRequestedChannelGroup)),
image->texture(mImage->channelsInGroup(mRequestedChannelGroup), mMinFilter, mMagFilter),
// The uber shader operates in [-1, 1] coordinates and requires the _inserve_ image transform to obtain texture coordinates in
// [0, 1]-space.
inverse(transform(image)),
Expand All @@ -104,13 +104,13 @@ void ImageCanvas::draw_contents() {
2.0f * inverse(Vector2f{m_size}) / mPixelRatio,
Vector2f{20.0f},
!mSupportsHdr,
mImage->texture(mRequestedChannelGroup),
mImage->texture(mImage->channelsInGroup(mRequestedChannelGroup), mMinFilter, mMagFilter),
// The uber shader operates in [-1, 1] coordinates and requires the _inserve_ image transform to obtain texture coordinates in [0,
// 1]-space.
inverse(transform(mImage.get())),
// We're passing the channels found in `mImage` such that, if some channels don't exist in `mReference`, they're filled with default
// values (0 for colors, 1 for alpha).
mReference->texture(mImage->channelsInGroup(mRequestedChannelGroup)),
mReference->texture(mImage->channelsInGroup(mRequestedChannelGroup), mMinFilter, mMagFilter),
inverse(transform(mReference.get())),
mExposure,
mOffset,
Expand Down
22 changes: 22 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <tev/Common.h>
#include <tev/Image.h>
#include <tev/ImageViewer.h>
#include <tev/Ipc.h>
Expand Down Expand Up @@ -246,6 +247,19 @@ static int mainFunc(const vector<string>& arguments) {
{'m', "metric"},
};

ValueFlag<string> minFilterFlag{
parser,
"MIN FILTER",
"The filter to use when downsampling (minifying) images.",
{"min-filter"},
};
ValueFlag<string> magFilterFlag{
parser,
"MAG FILTER",
"The filter to use when upsampling (magnifying) images.",
{"mag-filter"},
};

Flag newWindowFlagOn{
parser,
"NEW WINDOW",
Expand Down Expand Up @@ -569,6 +583,14 @@ static int mainFunc(const vector<string>& arguments) {
sImageViewer->setMetric(toMetric(get(metricFlag)));
}

if (minFilterFlag) {
sImageViewer->setMinFilter(toInterpolationMode(get(minFilterFlag)));
}

if (magFilterFlag) {
sImageViewer->setMagFilter(toInterpolationMode(get(magFilterFlag)));
}

if (offsetFlag) {
sImageViewer->setOffset(get(offsetFlag));
}
Expand Down
Loading